home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / ada / gnat1792.zip / gnat179b / t-adainc / a-teioau.adb < prev    next >
Text File  |  1994-05-19  |  80KB  |  3,156 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                         GNAT RUNTIME COMPONENTS                          --
  4. --                                                                          --
  5. --                      A D A . T E X T _ I O . A U X                       --
  6. --                                                                          --
  7. --                                 B o d y                                  --
  8. --                                                                          --
  9. --                            $Revision: 1.19 $                             --
  10. --                                                                          --
  11. --           Copyright (c) 1992,1993,1994 NYU, All Rights Reserved          --
  12. --                                                                          --
  13. -- GNAT is free software;  you can  redistribute it  and/or modify it under --
  14. -- terms of the  GNU General Public License as published  by the Free Soft- --
  15. -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
  16. -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
  17. -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  18. -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
  19. -- for  more details.  You should have  received  a copy of the GNU General --
  20. -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
  21. -- to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. --
  22. --                                                                          --
  23. ------------------------------------------------------------------------------
  24.  
  25. with System; use System;
  26.  
  27. package body Ada.Text_IO.Aux is
  28.  
  29.    ----------------
  30.    -- Local Data --
  31.    ----------------
  32.  
  33.    Max_Num_Of_Files : constant := 60;
  34.  
  35.    Line_Feed : constant Character := Ascii.Lf;  --  Character'Val (16#0A#);
  36.    Nul       : constant Character := Ascii.Nul; --  Character'Val (16#00#);
  37.    Page_Mark : constant Character := Ascii.Ff;  --  Character'Val (16#0C#);
  38.  
  39.    --  The term "file" here is used in the same way as in the Ada Reference
  40.    --  Manual, that is it refers to an object of some "file_type". Otherwise
  41.    --  "external file" is used.
  42.  
  43.    Open_Files : array (1 .. Max_Num_Of_Files) of File_Type;
  44.    --  Used to make sure we don't open too many files and that we do not
  45.    --  open the same file twice.
  46.  
  47.    Standard_In    : File_Type;
  48.    Standard_Out   : File_Type;
  49.    Standard_Err   : File_Type;
  50.  
  51.    Scanning_From_File : Boolean;
  52.    --  Determines if characters are read from a File (True) or String (False).
  53.  
  54.    type Temp_File_Rec;
  55.    type Link is access Temp_File_Rec;
  56.  
  57.    type Temp_File_Rec is record
  58.       File_Name : Pstring;
  59.       Next      : Link;
  60.    end record;
  61.  
  62.    Temp_Files : Link;
  63.  
  64.    type Work_String_Type is array (0 .. 1023) of Character;
  65.    Work_String  : Work_String_Type;
  66.    WS_Length    : Natural := 0;
  67.    WS_Index1    : Natural := 0;
  68.    WS_Index2    : Natural := 0;
  69.  
  70.    ------------------------
  71.    --  Local Subprograms --
  72.    ------------------------
  73.  
  74.    procedure Allocate_AFCB;
  75.    --  Determine which AFCB in the Open_Files table is available to be used
  76.    --  for the current file.
  77.  
  78.    function Alpha (C : Character) return Boolean;
  79.    --  Predicate to test if Character argument is an upper or lower case
  80.    --  letter, returns True if the argument is a letter, False if not.
  81.  
  82.    function Alphanum (C : Character) return Boolean;
  83.    --  Predicate to test if Character is an upper or lower case letter
  84.    --  or a digit. Returns True if the arguement is a letter or a digit,
  85.    --  False if not.
  86.  
  87.    procedure Check_Digit;
  88.    --  Assert that the next Character is a digit otherwise raise Data_Error.
  89.  
  90.    procedure Check_Extended_Digit;
  91.    --  Assert that the next Character is an extended digit otherwise raise
  92.    --  Data_Error.
  93.  
  94.    procedure Check_File_Open;
  95.    --  Check if the current file is open or not. If the file is not open,
  96.    --  then Status_Error is raised. Otherwise control returns normally.
  97.  
  98.    procedure Check_Hash (C : Character);
  99.    --  Determine if next Character is matching hash, raise Data_Error if not.
  100.    --  Stores '#' in Work_String.
  101.  
  102.    procedure Check_Multiple_File_Opens;
  103.  
  104.    procedure Check_Opened_Ok;
  105.    --  Check that an Fopen succeeded, raise Name_Error if not
  106.  
  107.    procedure Check_Status_And_Mode (C_Mode : File_Mode);
  108.    --  If the current file is not open, then Status_Error is raised. If
  109.    --  the file is open, then the mode is checked against the argument which
  110.    --  is the desired mode for the operation. If it does not match, then
  111.    --  Mode_Error is raised, otherwise control returns normally.
  112.  
  113.    procedure Check_Status_And_Mode (C_Mode1, C_Mode2 : File_Mode);
  114.    --  If the current file is not open, then Status_Error is raised. If
  115.    --  the file is open, then the mode is checked against the arguments which
  116.    --  are the desired modes for the operation. If it does not match either
  117.    --  one of them, Mode_Error is raised, otherwise control returns normally.
  118.  
  119.    procedure Close_File;
  120.    --  Close file and deallocate the AFCB back to the pool.
  121.  
  122.    procedure Copy_Integer;
  123.    --  This procedure copies a string with the syntax of "based_Integer" from
  124.    --  the input to the Work_String. Underscores are allowed but not copied.
  125.  
  126.    procedure Copy_Based_Integer;
  127.    --  This procedure copies a string with the syntax of "based_Integer" from
  128.    --  the input to the Work_String. Underscores are allowed but not copied.
  129.  
  130.    procedure Copyc;
  131.    --  Copy the next input Character to Work_String using WS_Index2
  132.  
  133.    function Digit (C : Character) return Boolean;
  134.    --  Predicate if C corresponds to the digits 0 thru 9.
  135.  
  136.    function Extended_Digit (C : Character) return Boolean;
  137.    --  Predicate if C corresponds to the digits 0 thru 9 or letters A thru F.
  138.  
  139.    function Graphic (C : Character) return Boolean;
  140.    --  Predicate to test if the Character is an Ascii graphic letter.
  141.    --  True if the argument is an Ascii graphic character, False otherwise.
  142.  
  143.    function Getcp return Character;
  144.    --  Gets the next Character from the string or file being scanned according
  145.    --  to the setting of Scanning_From_File. In string mode, WS_Index1 is
  146.    --  updated. If no more Characters remain to be scanned, End_Error is
  147.    --  raised.
  148.  
  149.    function Get_Char return Character;
  150.    --  Get the next character from the current text input file. If no
  151.    --  character is available, End_Error is raised.
  152.  
  153.    procedure Image_Float (Item : Float; Aft, Exp : Field);
  154.    --  Creates a string image of Item where Aft and Exp control the format
  155.    --  according to the rules in 14.3.8. The result is placed in Work_String.
  156.  
  157.    procedure Image_Integer (Item : Integer; Base : Integer);
  158.    --  Creates a string image of Item using the given Base and places it
  159.    --  Work_String. If an out of range value or a bad character is
  160.    --  encountered, Data_Error is raised.
  161.  
  162.    procedure Make_Temp_File_Name;
  163.    --  Generate a unique file name and use it for the name of the current file.
  164.  
  165.    function Nextc return Character;
  166.    --  Return the next Character to be read from the string file being
  167.    --  scanned, according to the setting of Scanning_From_File. In string
  168.    --  mode WS_Index1 is updated. If we are currently at the end of string
  169.    --  then a line feed is returned.
  170.  
  171.    function Page_Is_Not_Terminated return Boolean;
  172.    --  Indicates whether the current page of current file is not terminated.
  173.  
  174.    procedure Put_Blanks (N : Integer);
  175.    --  Write N blanks to the output. There is no check for line overflow, it
  176.    --  is assumed that the caller has already checked for this.
  177.  
  178.    procedure Put_Buffer
  179.      (Width    : Integer;
  180.       Pad_Type : Character;
  181.       Length : Integer);
  182.    --  Need documentation ???
  183.  
  184.    procedure Put_Line1;
  185.    --  Outputs a line feed to the current text file
  186.  
  187.    procedure Put_Page;
  188.    --  Write a page mark to current text file.
  189.  
  190.    procedure Load_Look_Ahead (End_Of_File_Flag : Boolean);
  191.    --  This procedure loads the lookahead for a TEXT_IO input file, leaving
  192.    --  CHARS set to 3 (unless the file is less than 3 bytes long), and CHAR1
  193.    --  CHAR2 and CHAR3 containing the initial characters of the file. A special
  194.    --  exception occurs when the standard input file is the keyboard in which
  195.    --  case we only read 1 character because of interactive I/O except when
  196.    --  load_look_ahead is called in the case of END_OF_FILE where we want to
  197.    --  read 2 characters to check for the EOT character. The parameter to this
  198.    --  routine end_of_file_flag is TRUE when processing for and END_OF_FILE
  199.    --  situation and is FALSE otherwise.
  200.  
  201.    procedure Range_Error;
  202.    --  Procedure called if scanned number is out of range.
  203.  
  204.    function Scan_Based_Int (Base : Integer) return Integer;
  205.  
  206.    procedure Scan_Blanks;
  207.    --  Routine to scan past leading blanks to find first non-blank.
  208.    --  Leaves WS_Index1 pointing to first non-blank character.
  209.  
  210.    procedure Scan_Enum (Last : out Natural);
  211.    --  Procedure to scan an Ada enumeration literal, which maybe an identifier
  212.    --  or a character literal. The input may be from a file or from a string
  213.    --  depending the setting of the Scanning_From_File flag. The result is
  214.    --  stored in Work_String.
  215.  
  216.    function Scan_Int return Integer;
  217.    --  This routine scans an Integer value from the string pointed by the
  218.    --  global Integer WS_Index2. On exit WS_Index2 is updated to point to
  219.    --  the first
  220.    --  non-digit. The result returned is always negative. This allows the
  221.    --  largest negative Integer value to be properly stored and converted.
  222.    --  A value of +1 returned indicated that overflow occured.
  223.  
  224.    procedure Scan_Integer (Width : Integer; Result : out Integer);
  225.    --  Procedure to scan an Ada Integer value and return the Integer result
  226.    --  The parameter Width specifies the width of the field (zero means an
  227.    --  unlimited scan). The input is from the current TEXT_IO input file.
  228.  
  229.    procedure Scan_Integer_String (Last : out Integer; Result : out Integer);
  230.    --  Procedure to scan an ada integer value and store it in Result.
  231.    --  The input is from the string stored in Work_String. Last is set to
  232.    --  the count of Characters scanned.
  233.  
  234.    procedure Scan_Integer_Val (Fixed_Field : Boolean; Result : out Integer);
  235.    --  Procedure to scan an Ada Integer value and return the Integer result.
  236.  
  237.    function Scan_Float (Width : Natural) return Float;
  238.    --  Procedure to scan an Ada float value and return the float result.
  239.    --  The width specifies the width of the field(zero = unlimited scan).
  240.    --  For this case, the input is from the current TEXT_IO input file.
  241.  
  242.    procedure Scan_Float_String (Last : out Integer; Result : out Float);
  243.    --  Procedure to scan an Ada float value and return the integer result.
  244.    --  The width specifies the width of the field(zero = unlimited scan).
  245.    --  For this case, the input is from the string stored in work_string. On
  246.    --  return, last is the count of characters scanned minus one.
  247.  
  248.    function Scan_Float_Val (Fixed_Field : Boolean) return Float;
  249.    --  Procedure to scan an Ada float value and return the float result. The
  250.    --  parameter num_type is a pointer to the type template for the float type.
  251.  
  252.    function Scan_Real_Val (Fixed_Field : Boolean) return Long_Float;
  253.    --  Procedure to scan a real value and return the result as a double real.
  254.    --  A range exception is signalled if the value is out of range of allowed
  255.    --  Ada real values, but no other range check is made.
  256.  
  257.    procedure Setup_Fixed_Field (Width : Integer);
  258.    --  This procedure is used for numeric conversions where the field to be
  259.    --  scanned has a fixed width (i.e. width parameter is non-zero).
  260.    --  It acquires the field from the input file and copies it to Work_String.
  261.    --  It returns to the caller ready to scan the data from work_string.
  262.  
  263.    function Sign (C : Character) return Boolean;
  264.    --  Predicate indicating whether character C is '+' or '-'
  265.  
  266.    procedure Skipc;
  267.    --  This procedure skips the next input Character.
  268.  
  269.    procedure Test_Fixed_Field_End;
  270.    --  this procedure is called after scanning an item from a fixed length
  271.    --  field to ensure that only blanks remain in the field. An exception
  272.    --  is raised if there are any unexpected non-blank Characters left in
  273.    --  the field.
  274.  
  275.    function Upper_Case (C : Character) return Character;
  276.    --  Converts character C to upper case if necessary
  277.  
  278.    procedure Unimplemented (Message : String) is
  279.    begin
  280.       Text_IO.Put (Message);
  281.       Text_IO.Put_Line (" not implemented yet");
  282.    end Unimplemented;
  283.  
  284.    procedure Word_Mul
  285.      (A : Integer;
  286.       B : Integer;
  287.       O : out Boolean;
  288.       R : out Integer);
  289.    --  Multiply with overflow check (use until trapping arithmetic works).
  290.  
  291.    procedure Word_Sub
  292.      (A : Integer;
  293.       B : Integer;
  294.       O : out Boolean;
  295.       R : out Integer);
  296.    --  Subtraction with overflow check (use until trapping arithmetic works)
  297.  
  298.    --  Interface with system calls
  299.  
  300.    procedure C_Fgetc
  301.      (F      : Text_IO.File_Ptr;
  302.       C      : out Character;
  303.       Is_Eof : out Boolean);
  304.  
  305.    procedure Fclose (P : Text_IO.File_Ptr);
  306.  
  307.    function  Fopen (Name : String; Typ : File_Mode) return Text_IO.File_Ptr;
  308.  
  309.    procedure Fputc (F : Text_IO.File_Ptr; C : Character);
  310.  
  311.    function  Isatty (F : Text_IO.File_Ptr) return Boolean;
  312.  
  313.    function  Stdin return Text_IO.File_Ptr;
  314.  
  315.    function  Stdout return Text_IO.File_Ptr;
  316.  
  317.    function  Stderr return Text_IO.File_Ptr;
  318.  
  319.    procedure Unlink (Name : String);
  320.  
  321.    -----------
  322.    -- Chars --
  323.    -----------
  324.  
  325.    function Chars return Integer is
  326.    begin
  327.       return The_File.Count;
  328.    end Chars;
  329.  
  330.    ---------------
  331.    -- Set_Chars --
  332.    ---------------
  333.  
  334.    procedure Set_Chars (Val : Integer) is
  335.    begin
  336.       The_File.Count := Val;
  337.    end Set_Chars;
  338.  
  339.    -----------
  340.    -- Char1 --
  341.    -----------
  342.  
  343.    function Char1 return Character is
  344.    begin
  345.       return The_File.Look_Ahead (1);
  346.    end Char1;
  347.  
  348.    ---------------
  349.    -- Set_Char1 --
  350.    ---------------
  351.  
  352.    procedure Set_Char1 (Val : Character) is
  353.    begin
  354.       The_File.Look_Ahead (1) := Val;
  355.    end Set_Char1;
  356.  
  357.    -----------
  358.    -- Char2 --
  359.    -----------
  360.  
  361.    function Char2 return Character is
  362.    begin
  363.       return The_File.Look_Ahead (2);
  364.    end Char2;
  365.  
  366.    ---------------
  367.    -- Set_Char2 --
  368.    ---------------
  369.  
  370.    procedure Set_Char2 (Val : Character) is
  371.    begin
  372.       The_File.Look_Ahead (2) := Val;
  373.    end Set_Char2;
  374.  
  375.    -----------
  376.    -- Char3 --
  377.    -----------
  378.  
  379.    function Char3 return Character is
  380.    begin
  381.       return The_File.Look_Ahead (3);
  382.    end Char3;
  383.  
  384.    ---------------
  385.    -- Set_Char3 --
  386.    ---------------
  387.  
  388.    procedure Set_Char3 (Val : Character) is
  389.    begin
  390.       The_File.Look_Ahead (3) := Val;
  391.    end Set_Char3;
  392.  
  393.    ------------
  394.    -- Create --
  395.    ------------
  396.  
  397.    procedure Create
  398.      (File : in out File_Type;
  399.       Mode : in File_Mode := Out_File;
  400.       Name : in String := "";
  401.       Form : in String := "") is
  402.  
  403.    begin
  404.       The_File := File;
  405.  
  406.       if The_File /= null then
  407.          raise Status_Error; --  File already open
  408.       elsif Mode = In_File then
  409.          raise Use_Error;    -- Unsupported file access
  410.       end if;
  411.  
  412.       Allocate_AFCB;
  413.       The_File.Name := new String'(Name);
  414.       The_File.Form := new String'(Form);
  415.       The_File.Mode := Mode;
  416.  
  417.       if Name'Length = 0 then
  418.          Make_Temp_File_Name;
  419.       end if;
  420.  
  421.       Check_Multiple_File_Opens;
  422.       The_File.AFCB_In_Use := True;
  423.       The_File.Desc := Fopen (The_File.Name.all, Out_File);
  424.       Check_Opened_Ok;
  425.  
  426.       The_File.Page := 1;
  427.       The_File.Line := 1;
  428.       The_File.Col := 1;
  429.       The_File.Line_Length := 0;
  430.       The_File.Page_Length := 0;
  431.       File := The_File;
  432.    end Create;
  433.  
  434.    ----------
  435.    -- Open --
  436.    ----------
  437.  
  438.    procedure Open
  439.      (File : in out File_Type;
  440.       Mode : in File_Mode;
  441.       Name : in String;
  442.       Form : in String := "") is
  443.  
  444.    begin
  445.       The_File := File;
  446.  
  447.       if The_File /= null then
  448.          raise Status_Error; --  File already open
  449.       end if;
  450.  
  451.       Allocate_AFCB;
  452.       The_File.Name := new String'(Name);
  453.       The_File.Form := new String'(Form);
  454.       The_File.Mode := Mode;
  455.  
  456.       if Name'Length = 0 then
  457.          Make_Temp_File_Name;
  458.       end if;
  459.  
  460.       Check_Multiple_File_Opens;
  461.       The_File.AFCB_In_Use := True;
  462.  
  463.       if Mode = In_File then
  464.          The_File.Desc := Fopen (Name, In_File);
  465.          Check_Opened_Ok;
  466.          Set_Chars (0);
  467.       else
  468.          The_File.Desc := Fopen (Name, Out_File);
  469.          Check_Opened_Ok;
  470.       end if;
  471.  
  472.       The_File.Page := 1;
  473.       The_File.Line := 1;
  474.       The_File.Col := 1;
  475.       The_File.Line_Length := 0;
  476.       The_File.Page_Length := 0;
  477.       File := The_File;
  478.    end Open;
  479.  
  480.    -----------
  481.    -- Close --
  482.    -----------
  483.  
  484.    procedure Close (File : in out File_Type) is
  485.    begin
  486.       The_File := File;
  487.       Check_File_Open;
  488.  
  489.       if The_File.Mode = Out_File or else The_File.Mode = Append_File then
  490.  
  491.          --  Simulate effect of NEW_PAGE unless current page is terminated
  492.  
  493.          if Page_Is_Not_Terminated then
  494.             if The_File.Col > 1
  495.               or else (The_File.Col = 1 and then The_File.Line = 1)
  496.             then
  497.                Put_Line1;
  498.             end if;
  499.  
  500.             Put_Page;
  501.          end if;
  502.       end if;
  503.  
  504.       --  If the file being closed is one of the default files, set the default
  505.       --  file indicator to null to indicate that the file is closed.
  506.  
  507.       if The_File = Current_In then
  508.          Current_In := null;
  509.       elsif The_File = Current_Out then
  510.          Current_Out := null;
  511.       elsif The_File = Current_Err then
  512.          Current_Err := null;
  513.       end if;
  514.  
  515.       --  Sever the association between the given file and its associated
  516.       --  external file. The given file is left closed. Do not perform system
  517.       --  closes on the standard input, output and error files.
  518.  
  519.       if The_File /= Standard_In
  520.         and then The_File /= Standard_Out
  521.         and then The_File /= Standard_Err
  522.       then
  523.          Close_File;
  524.       end if;
  525.  
  526.       The_File := null;
  527.       File := The_File;
  528.    end Close;
  529.  
  530.    ------------
  531.    -- Delete --
  532.    ------------
  533.  
  534.    procedure Delete (File : in out File_Type) is
  535.       File_Name_To_Delete : Pstring;
  536.  
  537.    begin
  538.       The_File := File;
  539.       Check_File_Open;
  540.       File_Name_To_Delete := new String'(The_File.Name.all);
  541.       Close (The_File);
  542.       Unlink (File_Name_To_Delete.all);
  543.       File := The_File;
  544.    end Delete;
  545.  
  546.    -----------
  547.    -- Reset --
  548.    -----------
  549.  
  550.    procedure Reset
  551.      (File : in out File_Type;
  552.       Mode : in File_Mode)
  553.    is
  554.    begin
  555.       The_File := File;
  556.       Check_File_Open;
  557.  
  558.       if (The_File = Current_In
  559.             or else The_File = Current_Out
  560.             or else The_File = Current_Err)
  561.           and then The_File.Mode /= Mode
  562.       then
  563.          raise Mode_Error;  --  "Cannot change mode"
  564.       end if;
  565.  
  566.       if The_File.Mode = Out_File or else The_File.Mode = Append_File then
  567.  
  568.          --  Simulate NEW_PAGE unless current page already terminated
  569.  
  570.          if Page_Is_Not_Terminated then
  571.             if The_File.Col > 1
  572.               or else (The_File.Col = 1 and then The_File.Line = 1)
  573.             then
  574.                Put_Line1;
  575.             end if;
  576.  
  577.             Put_Page;
  578.          end if;
  579.       end if;
  580.  
  581.       Fclose (The_File.Desc);
  582.  
  583.       if Mode = In_File then
  584.          The_File.Desc := Fopen (The_File.Name.all, In_File);
  585.          Check_Opened_Ok;
  586.       else
  587.          The_File.Desc := Fopen (The_File.Name.all, Out_File);
  588.          Check_Opened_Ok;
  589.          The_File.Line_Length := 0;
  590.          The_File.Page_Length := 0;
  591.       end if;
  592.  
  593.       The_File.Mode := Mode;
  594.       Set_Chars (0);
  595.       The_File.Col := 1;
  596.       The_File.Line := 1;
  597.       The_File.Page := 1;
  598.       File := The_File;
  599.    end Reset;
  600.  
  601.    ----------
  602.    -- Mode --
  603.    ----------
  604.  
  605.    function Mode (File : in File_Type) return File_Mode is
  606.    begin
  607.       The_File := File;
  608.       Check_File_Open;
  609.       return The_File.Mode;
  610.    end Mode;
  611.  
  612.    ----------
  613.    -- Name --
  614.    ----------
  615.  
  616.    function Name (File : in File_Type) return String is
  617.    begin
  618.       The_File := File;
  619.       Check_File_Open;
  620.       return The_File.Name.all;
  621.    end Name;
  622.  
  623.    ----------
  624.    -- Form --
  625.    ----------
  626.  
  627.    function Form (File : in File_Type) return String is
  628.    begin
  629.       The_File := File;
  630.       Check_File_Open;
  631.       return The_File.Form.all;
  632.    end Form;
  633.  
  634.    -------------
  635.    -- Is_Open --
  636.    -------------
  637.  
  638.    function Is_Open (File : in File_Type) return Boolean is
  639.    begin
  640.       The_File := File;
  641.       return The_File /= null;
  642.    end Is_Open;
  643.  
  644.    ---------------
  645.    -- Set_Input --
  646.    ---------------
  647.  
  648.    procedure Set_Input (File : in File_Type) is
  649.    begin
  650.       The_File := File;
  651.       Check_Status_And_Mode (In_File);
  652.       Current_In := The_File;
  653.    end Set_Input;
  654.  
  655.    ----------------
  656.    -- Set_Output --
  657.    ----------------
  658.  
  659.    procedure Set_Output (File : in File_Type) is
  660.    begin
  661.       The_File := File;
  662.       Check_Status_And_Mode (Out_File, Append_File);
  663.       Current_Out := The_File;
  664.    end Set_Output;
  665.  
  666.    ---------------
  667.    -- Set_Error --
  668.    ---------------
  669.  
  670.    procedure Set_Error (File : in File_Type) is
  671.    begin
  672.       The_File := File;
  673.       Check_Status_And_Mode (Out_File, Append_File);
  674.       Current_Err := The_File;
  675.    end Set_Error;
  676.  
  677.    --------------------
  678.    -- Standard_Input --
  679.    --------------------
  680.  
  681.    function Standard_Input return File_Type is
  682.    begin
  683.       return Standard_In;
  684.    end Standard_Input;
  685.  
  686.    ---------------------
  687.    -- Standard_Output --
  688.    ---------------------
  689.  
  690.    function Standard_Output return File_Type is
  691.    begin
  692.       return Standard_Out;
  693.    end Standard_Output;
  694.  
  695.    --------------------
  696.    -- Standard_Error --
  697.    --------------------
  698.  
  699.    function Standard_Error return File_Type is
  700.    begin
  701.       return Standard_Err;
  702.    end Standard_Error;
  703.  
  704.    -------------------
  705.    -- Current_Input --
  706.    -------------------
  707.  
  708.    function Current_Input return File_Type is
  709.    begin
  710.       return Current_In;
  711.    end Current_Input;
  712.  
  713.    --------------------
  714.    -- Current_Output --
  715.    --------------------
  716.  
  717.    function Current_Output return File_Type is
  718.    begin
  719.       return Current_Out;
  720.    end Current_Output;
  721.  
  722.    -------------------
  723.    -- Current_Error --
  724.    -------------------
  725.  
  726.    function Current_Error return File_Type is
  727.    begin
  728.       return Current_Err;
  729.    end Current_Error;
  730.  
  731.    ---------------------
  732.    -- Set_Line_Length --
  733.    ---------------------
  734.  
  735.    procedure Set_Line_Length (File : in File_Type; To : in Count) is
  736.    begin
  737.       The_File := File;
  738.       Check_Status_And_Mode (Out_File, Append_File);
  739.       The_File.Line_Length := To;
  740.    end Set_Line_Length;
  741.  
  742.    -----------------
  743.    -- Line_Length --
  744.    -----------------
  745.  
  746.    function Line_Length (File : in File_Type) return Count is
  747.    begin
  748.       The_File := File;
  749.       Check_Status_And_Mode (Out_File, Append_File);
  750.       return The_File.Line_Length;
  751.    end Line_Length;
  752.  
  753.    ---------------------
  754.    -- Set_Page_Length --
  755.    ---------------------
  756.  
  757.    procedure Set_Page_Length (File : in File_Type; To : in Count) is
  758.    begin
  759.       The_File := File;
  760.       Check_Status_And_Mode (Out_File, Append_File);
  761.       The_File.Page_Length := To;
  762.    end Set_Page_Length;
  763.  
  764.    -----------------
  765.    -- Page_Length --
  766.    -----------------
  767.  
  768.    function Page_Length (File : in File_Type) return Count is
  769.    begin
  770.       The_File := File;
  771.       Check_Status_And_Mode (Out_File, Append_File);
  772.       return The_File.Page_Length;
  773.    end Page_Length;
  774.  
  775.    --------------
  776.    -- New_Line --
  777.    --------------
  778.  
  779.    procedure New_Line
  780.      (File    : in File_Type;
  781.       Spacing : in Positive_Count := 1) is
  782.  
  783.    begin
  784.       The_File := File;
  785.       Check_Status_And_Mode (Out_File, Append_File);
  786.  
  787.       for J in 1 .. Spacing loop
  788.          Put_Line1;
  789.       end loop;
  790.    end New_Line;
  791.  
  792.    ---------------
  793.    -- Skip_Line --
  794.    ---------------
  795.  
  796.    procedure Skip_Line
  797.      (File    : in File_Type;
  798.       Spacing : in Positive_Count := 1)
  799.    is
  800.       C : Character;
  801.  
  802.    begin
  803.       The_File := File;
  804.       Check_Status_And_Mode (In_File);
  805.  
  806.       for J in 1 .. Spacing loop
  807.          loop
  808.             Load_Look_Ahead (False);
  809.             exit when Get_Char = Line_Feed;
  810.          end loop;
  811.  
  812.          --  Ignore page marks when reading from a terminal.
  813.  
  814.          if Isatty (The_File.Desc) then
  815.             return;
  816.          end if;
  817.  
  818.          loop
  819.             Load_Look_Ahead (False);
  820.             exit when Char1 /= Page_Mark;
  821.             C := Get_Char;
  822.          end loop;
  823.       end loop;
  824.    end Skip_Line;
  825.  
  826.    -----------------
  827.    -- End_Of_Line --
  828.    -----------------
  829.  
  830.    function End_Of_Line (File : in File_Type) return boolean is
  831.    begin
  832.       The_File := File;
  833.       Check_Status_And_Mode (In_File);
  834.       Load_Look_Ahead (False);
  835.       return Chars = 0 or else Char1 = Line_Feed;
  836.    end End_Of_Line;
  837.  
  838.    --------------
  839.    -- New_Page --
  840.    --------------
  841.  
  842.    procedure New_Page (File : in File_Type) is
  843.    begin
  844.       The_File := File;
  845.       Check_Status_And_Mode (Out_File, Append_File);
  846.  
  847.       if The_File.Col > 1
  848.        or else (The_File.Col = 1 and then The_File.Line = 1)
  849.       then
  850.          Put_Line1;
  851.       end if;
  852.  
  853.       Put_Page;
  854.    end New_Page;
  855.  
  856.    ---------------
  857.    -- Skip_Page --
  858.    ---------------
  859.  
  860.    procedure Skip_Page (File : in File_Type) is
  861.    begin
  862.       The_File := File;
  863.       Check_Status_And_Mode (In_File);
  864.  
  865.       while Get_Char /= Page_Mark loop
  866.          null;
  867.       end loop;
  868.    end Skip_Page;
  869.  
  870.    -----------------
  871.    -- End_Of_Page --
  872.    -----------------
  873.  
  874.    function End_Of_Page (File : in File_Type) return Boolean is
  875.    begin
  876.       The_File := File;
  877.       Check_Status_And_Mode (In_File);
  878.  
  879.       if Isatty (The_File.Desc) then
  880.          return False;
  881.       end if;
  882.  
  883.       Load_Look_Ahead (False);
  884.  
  885.       if Chars > 1 then
  886.          return Char1 = Line_Feed and then Char2 = Page_Mark;
  887.       elsif Chars = 1 then
  888.          return Char1 = Line_Feed;
  889.       else
  890.          return True;
  891.       end if;
  892.    end End_Of_Page;
  893.  
  894.    -----------------
  895.    -- End_Of_File --
  896.    -----------------
  897.  
  898.    function End_Of_File (File : in File_Type) return Boolean is
  899.    begin
  900.       The_File := File;
  901.       Check_Status_And_Mode (In_File);
  902.       Load_Look_Ahead (True);
  903.  
  904.       if Isatty (The_File.Desc) then
  905.          if Chars = 2 then
  906.             return False;
  907.          elsif Chars = 1 then
  908.             return Char1 = Line_Feed;
  909.          elsif Chars = 0 then
  910.             return True;
  911.          end if;
  912.       else
  913.          if Chars = 2 then
  914.             return Char1 = Line_Feed and then Char2 = Page_Mark;
  915.          elsif Chars = 1 then
  916.             return Char1 = Line_Feed;
  917.          elsif Chars = 0 then
  918.             return True;
  919.          else --  Chars = 3
  920.             return False;
  921.          end if;
  922.       end if;
  923.    end End_Of_File;
  924.  
  925.    -------------
  926.    -- Set_Col --
  927.    -------------
  928.  
  929.    procedure Set_Col (File : in File_Type; To : in Positive_Count) is
  930.       C : Character;
  931.  
  932.    begin
  933.       The_File := File;
  934.       Check_File_Open;
  935.  
  936.       if The_File.Mode = In_File then
  937.  
  938.          --  SET_COL for file of mode In_File
  939.  
  940.          Load_Look_Ahead (False);
  941.  
  942.          while The_File.Col /= To
  943.            or else Char1 = Line_Feed
  944.            or else Char1 = Page_Mark
  945.          loop
  946.             C := Get_Char;
  947.          end loop;
  948.  
  949.       else
  950.  
  951.          --  SET_COL for file of mode Out_File or Append_File
  952.  
  953.          if The_File.Line_Length > 0
  954.            and then To > The_File.Line_Length
  955.          then
  956.             raise Layout_Error; --  "SET_COL past end of line"
  957.          end if;
  958.  
  959.          if To > The_File.Col then
  960.             Put_Blanks (Integer (To - The_File.Col));
  961.             The_File.Col := To;
  962.          elsif To < The_File.Col then
  963.             Put_Line1;
  964.             Put_Blanks (Integer (To - 1));
  965.             The_File.Col := To;
  966.          end if;
  967.       end if;
  968.    end Set_Col;
  969.  
  970.    --------------
  971.    -- Set_Line --
  972.    --------------
  973.  
  974.    procedure Set_Line (File : in File_Type; To : in Positive_Count) is
  975.       C : Character;
  976.  
  977.    begin
  978.       The_File := File;
  979.       Check_File_Open;
  980.  
  981.       if The_File.Mode = In_File then
  982.  
  983.          --  SET_LINE for file of mode In_File
  984.  
  985.          Load_Look_Ahead (False);
  986.  
  987.          while The_File.Line /= To
  988.            or else Char1 = Page_Mark
  989.          loop
  990.             C := Get_Char;
  991.          end loop;
  992.  
  993.       else
  994.  
  995.          --  SET_LINE for file of mode Out_File or Append_File
  996.  
  997.          if The_File.Page_Length > 0
  998.            and then To > The_File.Page_Length
  999.          then
  1000.             raise Layout_Error;  --  "Set_Line > Page_Length"
  1001.          end if;
  1002.  
  1003.          if To > The_File.Line  then
  1004.             for I in 1 .. To - The_File.Line loop
  1005.                Put_Line1;
  1006.             end loop;
  1007.          elsif To < The_File.Line then
  1008.             if The_File.Col > 1
  1009.               or else (The_File.Col = 1 and then The_File.Line = 1)
  1010.             then
  1011.                Put_Line1;
  1012.             end if;
  1013.  
  1014.             Put_Page;
  1015.  
  1016.             for J in 1 .. To - 1 loop
  1017.                Put_Line1;
  1018.             end loop;
  1019.          end if;
  1020.       end if;
  1021.    end Set_Line;
  1022.  
  1023.    ---------
  1024.    -- Col --
  1025.    ---------
  1026.  
  1027.    function Col (File : in File_Type) return Positive_Count is
  1028.    begin
  1029.       The_File := File;
  1030.       Check_File_Open;
  1031.  
  1032.       if The_File.Col > Count'Last then
  1033.          raise Layout_Error; --  "Col > Count'Last"
  1034.       end if;
  1035.  
  1036.       return The_File.Col;
  1037.    end Col;
  1038.  
  1039.    ----------
  1040.    -- Line --
  1041.    ----------
  1042.  
  1043.    function Line (File : in File_Type) return Positive_Count is
  1044.    begin
  1045.       The_File := File;
  1046.       Check_File_Open;
  1047.  
  1048.       if The_File.Line > Count'Last then
  1049.          raise Layout_Error; --  "Line > Count'Last"
  1050.       end if;
  1051.  
  1052.       return The_File.Line;
  1053.    end Line;
  1054.  
  1055.    ----------
  1056.    -- Page --
  1057.    ----------
  1058.  
  1059.    function Page (File : in File_Type) return Positive_Count is
  1060.    begin
  1061.       The_File := File;
  1062.       Check_File_Open;
  1063.  
  1064.       if The_File.Page > Count'Last then
  1065.          raise Layout_Error; --  "Page > Count'Last"
  1066.       end if;
  1067.  
  1068.       return The_File.Page;
  1069.    end Page;
  1070.  
  1071.    ---------
  1072.    -- Get --
  1073.    ---------
  1074.  
  1075.    procedure Get (Item : out Character) is
  1076.    begin
  1077.       Check_Status_And_Mode (In_File);
  1078.  
  1079.       loop
  1080.          Item := Get_Char;
  1081.          exit when Item /= Page_Mark and then Item /= Line_Feed;
  1082.       end loop;
  1083.    end Get;
  1084.  
  1085.    ---------
  1086.    -- Put --
  1087.    ---------
  1088.  
  1089.    procedure Put (Item : in Character) is
  1090.    begin
  1091.       Check_Status_And_Mode (Out_File, Append_File);
  1092.  
  1093.       if The_File.Line_Length /= 0
  1094.         and then The_File.Col > The_File.Line_Length
  1095.       then
  1096.          Put_Line1;
  1097.       end if;
  1098.  
  1099.       Fputc (The_File.Desc, Item);
  1100.       The_File.Col := The_File.Col + 1;
  1101.    end Put;
  1102.  
  1103.    ---------
  1104.    -- Get --
  1105.    ---------
  1106.  
  1107.    procedure Get (Item : out String) is
  1108.       J : Integer := 0;
  1109.       C : Character;
  1110.  
  1111.    begin
  1112.       Check_Status_And_Mode (In_File);
  1113.  
  1114.       while J < Item'Length loop
  1115.          C := Get_Char;
  1116.  
  1117.          if C /= Line_Feed and then C /= Page_Mark then
  1118.             Item (Item'First + J) := C;
  1119.             J := J + 1;
  1120.          end if;
  1121.       end loop;
  1122.    end Get;
  1123.  
  1124.    ---------
  1125.    -- Put --
  1126.    ---------
  1127.  
  1128.    procedure Put (Item : in String) is
  1129.    begin
  1130.       for J in Item'range loop
  1131.          Put (Item (J));
  1132.       end loop;
  1133.    end Put;
  1134.  
  1135.    --------------
  1136.    -- Put_Line --
  1137.    --------------
  1138.  
  1139.    procedure Put_Line (File : in File_Type; Item : in String) is
  1140.    begin
  1141.       The_File := File;
  1142.       Put (Item);
  1143.       New_Line (File, 1);
  1144.    end Put_Line;
  1145.  
  1146.    --------------
  1147.    -- Get_Line --
  1148.    --------------
  1149.  
  1150.    procedure Get_Line
  1151.      (File : in File_Type;
  1152.       Item : out String;
  1153.       Last : out Natural)
  1154.    is
  1155.       I_Length : Integer := Item'Length;
  1156.       Nstore   : Integer := 0;
  1157.  
  1158.    begin
  1159.       The_File := File;
  1160.       Check_Status_And_Mode (In_File);
  1161.  
  1162.       loop
  1163.          Load_Look_Ahead (False);
  1164.          exit when Nstore = I_Length;
  1165.  
  1166.          if Char1 = Line_Feed then
  1167.             Skip_Line (File, 1);
  1168.             exit;
  1169.          end if;
  1170.  
  1171.          Item (Item'First + Nstore) := Get_Char;
  1172.          Nstore := Nstore + 1;
  1173.       end loop;
  1174.  
  1175.       Last := Item'First + Nstore - 1;
  1176.    end Get_Line;
  1177.  
  1178.    -------------
  1179.    -- Get_Int --
  1180.    -------------
  1181.  
  1182.    procedure Get_Int
  1183.      (Item  : out Integer;
  1184.       Width : in Field := 0)
  1185.    is
  1186.    begin
  1187.       Check_Status_And_Mode (In_File);
  1188.       Scan_Integer (Width, Item);
  1189.    end Get_Int;
  1190.  
  1191.    -------------
  1192.    -- Put_Int --
  1193.    -------------
  1194.  
  1195.    procedure Put_Int
  1196.      (Item  : in Integer;
  1197.       Width : in Field;
  1198.       Base  : in Number_Base)
  1199.    is
  1200.    begin
  1201.       Check_Status_And_Mode (Out_File, Append_File);
  1202.       Image_Integer (Item, Base);
  1203.       Put_Buffer (Width, 'L', WS_Length);
  1204.    end Put_Int;
  1205.  
  1206.    -------------
  1207.    -- Get_Int --
  1208.    -------------
  1209.  
  1210.    procedure Get_Int
  1211.      (From : in String;
  1212.       Item : out Integer;
  1213.       Last : out Positive)
  1214.    is
  1215.    begin
  1216.       WS_Length := From'Length;
  1217.  
  1218.       for J in 0 .. WS_Length - 1 loop
  1219.          Work_String (J) := From (From'First + J);
  1220.       end loop;
  1221.  
  1222.       Work_String (WS_Length) := ' ';
  1223.       WS_Index1 := 0;
  1224.       Scan_Integer_String (Last, Item);
  1225.       Last := From'First + Last - 1;
  1226.    end Get_Int;
  1227.  
  1228.    -------------
  1229.    -- Put_Int --
  1230.    -------------
  1231.  
  1232.    procedure Put_Int
  1233.      (To   : out String;
  1234.       Item : in Integer;
  1235.       Base : in Number_Base)
  1236.    is
  1237.       To_Length : Integer := To'Length;
  1238.  
  1239.    begin
  1240.       Image_Integer  (Item, Base);
  1241.  
  1242.       if WS_Length > To_Length then
  1243.          raise Layout_Error;
  1244.       end if;
  1245.  
  1246.       for J in 0 .. To_Length - WS_Length - 1 loop
  1247.          To (To'First + J) := ' ';
  1248.       end loop;
  1249.  
  1250.       for J in To_Length - WS_Length .. To_Length - 1 loop
  1251.          To (To'First + J) := Work_String (J - To_Length + WS_Length);
  1252.       end loop;
  1253.    end Put_Int;
  1254.  
  1255.    ---------------
  1256.    -- Get_Float --
  1257.    ---------------
  1258.  
  1259.    procedure Get_Float
  1260.      (Item : out Float;
  1261.       Width : in Field)
  1262.    is
  1263.    begin
  1264.       Check_Status_And_Mode (In_File);
  1265.       Item := Scan_Float (Width);
  1266.    end Get_Float;
  1267.  
  1268.    ---------------
  1269.    -- Put_Float --
  1270.    ---------------
  1271.  
  1272.    procedure Put_Float
  1273.      (Item : in Float;
  1274.       Fore : in Field;
  1275.       Aft  : in Field;
  1276.       Exp  : in Field)
  1277.    is
  1278.    begin
  1279.       Check_Status_And_Mode (Out_File, Append_File);
  1280.       Image_Float (Item, Aft, Exp);
  1281.  
  1282.       if Exp = 0 then
  1283.          Put_Buffer (Aft + Fore + 1, 'L', WS_Length + 1);
  1284.       else
  1285.          Put_Buffer (Aft + Fore + Exp + 2, 'L', WS_Length + 1);
  1286.       end if;
  1287.    end Put_Float;
  1288.  
  1289.    ---------------
  1290.    -- Get_Float --
  1291.    ---------------
  1292.  
  1293.    procedure Get_Float
  1294.      (From : in String;
  1295.       Item : out Float;
  1296.       Last : out Positive)
  1297.    is
  1298.    begin
  1299.       WS_Length := From'Length;
  1300.  
  1301.       for J in 0 .. WS_Length - 1 loop
  1302.          Work_String (J) := From (From'First + J);
  1303.       end loop;
  1304.  
  1305.       Work_String (WS_Length) := ' ';
  1306.       WS_Index1 := 0;
  1307.       Scan_Float_String (Last, Item);
  1308.       Last := From'First + Last - 1;
  1309.    end Get_Float;
  1310.  
  1311.    ---------------
  1312.    -- Put_Float --
  1313.    ---------------
  1314.  
  1315.    procedure Put_Float
  1316.      (To   : out String;
  1317.       Item : in Float;
  1318.       Aft  : in Field;
  1319.       Exp  : in Field)
  1320.    is
  1321.       To_Length : Natural := To'Length;
  1322.  
  1323.    begin
  1324.       Image_Float (Item, Aft, Exp);
  1325.  
  1326.       if WS_Length > To_Length then
  1327.          raise Layout_Error;
  1328.       end if;
  1329.  
  1330.       for J in 0 .. To_Length - WS_Length - 1 loop
  1331.          To (To'First + J) := ' ';
  1332.       end loop;
  1333.  
  1334.       for J in To_Length - WS_Length .. To_Length - 1 loop
  1335.          To (To'First + J) := Work_String (J - To_Length + WS_Length);
  1336.       end loop;
  1337.    end Put_Float;
  1338.  
  1339.    --------------
  1340.    -- Get_Enum --
  1341.    --------------
  1342.  
  1343.    procedure Get_Enum (Str : out String; Len : out Positive) is
  1344.       Last : Positive;
  1345.  
  1346.    begin
  1347.       Check_Status_And_Mode (In_File);
  1348.       Scanning_From_File := True;
  1349.       Scan_Enum (Last);
  1350.  
  1351.       for J in 1 .. WS_Length loop
  1352.          Str (J) := Upper_Case (Work_String (J - 1));
  1353.       end loop;
  1354.  
  1355.       Len := WS_Length;
  1356.    end Get_Enum;
  1357.  
  1358.    --------------
  1359.    -- Get_Enum --
  1360.    --------------
  1361.  
  1362.    procedure Get_Enum
  1363.      (Str  : out String;
  1364.       From : in String;
  1365.       Len  : out Positive;
  1366.       Last : out Positive)
  1367.    is
  1368.    begin
  1369.       WS_Length := From'Length;
  1370.  
  1371.       for J in 0 .. WS_Length - 1 loop
  1372.          Work_String (J) := From (From'First + J);
  1373.       end loop;
  1374.  
  1375.       WS_Index1 := 0;
  1376.       Scanning_From_File := False;
  1377.       Scan_Enum (Last);
  1378.       Last := From'First + Last - 1;
  1379.  
  1380.       for J in 1 .. WS_Length loop
  1381.          Str (J) := Upper_Case (Work_String (J - 1));
  1382.       end loop;
  1383.  
  1384.       Len := WS_Length;
  1385.    end Get_Enum;
  1386.  
  1387.    --------------
  1388.    -- Put_Enum --
  1389.    --------------
  1390.  
  1391.    procedure Put_Enum
  1392.      (Item  : in String;
  1393.       Width : in Field;
  1394.       Set   : in Type_Set)
  1395.    is
  1396.       C : Character;
  1397.  
  1398.    begin
  1399.       Check_Status_And_Mode (Out_File, Append_File);
  1400.       WS_Length := Item'Length;
  1401.  
  1402.       for J in 0 .. WS_Length - 1 loop
  1403.          C := Item (Item'First + J);
  1404.  
  1405.          if Set = Lower_Case and then C in 'A' .. 'Z' then
  1406.             Work_String (J) := Character'Val (Character'Pos (C) + 32);
  1407.          else
  1408.             Work_String (J) := C;
  1409.          end if;
  1410.       end loop;
  1411.  
  1412.       Put_Buffer (Width, 'T', WS_Length);
  1413.    end Put_Enum;
  1414.  
  1415.    --------------
  1416.    -- Put_Enum --
  1417.    --------------
  1418.  
  1419.    procedure Put_Enum
  1420.      (To   : out String;
  1421.       Item : in String;
  1422.       Set  : in Type_Set)
  1423.    is
  1424.       Length : Integer := Item'Length;
  1425.       C      : Character;
  1426.  
  1427.    begin
  1428.       if Length > To'Length then
  1429.          raise Layout_Error;
  1430.       else
  1431.          for J in 0 .. Length - 1 loop
  1432.             C := Item (Item'First + J);
  1433.             if Set = Lower_Case and then C in 'A' .. 'Z' then
  1434.                To (To'First + J) := Character'Val (Character'Pos (C) + 32);
  1435.             else
  1436.                To (To'First + J) := C;
  1437.             end if;
  1438.          end loop;
  1439.  
  1440.          for J in Length .. To'Length - 1 loop
  1441.             To (To'First + J) := ' ';
  1442.          end loop;
  1443.       end if;
  1444.    end Put_Enum;
  1445.  
  1446.    --------------
  1447.    -- Put_Page --
  1448.    --------------
  1449.  
  1450.    procedure Put_Page is
  1451.    begin
  1452.       Fputc (The_File.Desc, Page_Mark);
  1453.       The_File.Page := The_File.Page + 1;
  1454.       The_File.Line := 1;
  1455.       The_File.Col := 1;
  1456.    end Put_Page;
  1457.  
  1458.    ---------------
  1459.    -- Put_Line1 --
  1460.    ---------------
  1461.  
  1462.    procedure Put_Line1 is
  1463.    begin
  1464.       Fputc (The_File.Desc, Line_Feed);
  1465.       The_File.Col := 1;
  1466.  
  1467.       if The_File.Page_Length > 0
  1468.          and The_File.Line >= The_File.Page_Length
  1469.       then
  1470.          Put_Page;
  1471.       else
  1472.          The_File.Line := The_File.Line + 1;
  1473.       end if;
  1474.    end Put_Line1;
  1475.  
  1476.    ---------------------
  1477.    -- Check_Opened_Ok --
  1478.    ---------------------
  1479.  
  1480.    procedure Check_Opened_Ok is
  1481.    begin
  1482.       if The_File.Desc = 0 then
  1483.          raise Name_Error; --  Error opening file due to invalid name
  1484.       end if;
  1485.    end Check_Opened_Ok;
  1486.  
  1487.    ---------------------
  1488.    -- Check_File_Open --
  1489.    ---------------------
  1490.  
  1491.    procedure Check_File_Open is
  1492.    begin
  1493.       --  There are two ways a file can appear closed. Either it is null
  1494.       --  which indicates that it was not used as an argument of an Open_Create
  1495.       --  call or it is not null but its Is_Open field is False which indicates
  1496.       --  that the file was used in an Open/Create but subsequently was closed.
  1497.  
  1498.       if The_File = null then
  1499.          raise Status_Error; --  File not open
  1500.       end if;
  1501.    end Check_File_Open;
  1502.  
  1503.    ---------------------------
  1504.    -- Check_Status_And_Mode --
  1505.    ---------------------------
  1506.  
  1507.    procedure Check_Status_And_Mode (C_Mode : File_Mode) is
  1508.    begin
  1509.       Check_File_Open;
  1510.  
  1511.       if The_File.Mode /= C_Mode then
  1512.          raise Mode_Error;
  1513.       end if;
  1514.    end Check_Status_And_Mode;
  1515.  
  1516.    ---------------------------
  1517.    -- Check_Status_And_Mode --
  1518.    ---------------------------
  1519.  
  1520.    procedure Check_Status_And_Mode (C_Mode1, C_Mode2 : File_Mode) is
  1521.    begin
  1522.       Check_File_Open;
  1523.  
  1524.       if The_File.Mode /= C_Mode1 and then The_File.Mode /= C_Mode2 then
  1525.          raise Mode_Error;
  1526.       end if;
  1527.    end Check_Status_And_Mode;
  1528.  
  1529.    -------------------
  1530.    -- Allocate_AFCB --
  1531.    --------------------
  1532.  
  1533.    procedure Allocate_AFCB is
  1534.       File_Num : Integer := Open_Files'First;
  1535.  
  1536.    begin
  1537.       --  Loop through the array of AFCBs stopping at the first vacate spot
  1538.       --  that is not currently being used.
  1539.  
  1540.       while File_Num <= Max_Num_Of_Files
  1541.         and then Open_Files (File_Num) /= null
  1542.         and then Open_Files (File_Num).AFCB_In_Use
  1543.       loop
  1544.          File_Num := File_Num + 1;
  1545.       end loop;
  1546.  
  1547.       --  No vacant spots were available since too many file are open
  1548.  
  1549.       if File_Num > Max_Num_Of_Files then
  1550.          raise Use_Error;  --  Too many files open
  1551.       end if;
  1552.  
  1553.       if Open_Files (File_Num) = null then
  1554.          Open_Files (File_Num) := new AFCB;
  1555.       end if;
  1556.  
  1557.       The_File := Open_Files (File_Num);
  1558.    end Allocate_AFCB;
  1559.  
  1560.    -------------------------
  1561.    -- Make_Temp_File_Name --
  1562.    -------------------------
  1563.  
  1564.    procedure Make_Temp_File_Name is
  1565.       Temp_File_Name  : String (1 .. 14);
  1566.       --  The template for temporary file name creation using Mktemp.
  1567.  
  1568.       procedure mktemp (S : Address);
  1569.       pragma Import (C, mktemp);
  1570.       --  mktemp creates a unique temporary file name given the address of
  1571.       --  a null terminated template.
  1572.  
  1573.    begin
  1574.       --  Create a template string which the call to mktemp will fill in to
  1575.       --  generate unique name file name.
  1576.  
  1577.       Temp_File_Name (1 .. 13) := "ADATEMPXXXXXX";
  1578.       Temp_File_Name (14) := Ascii.Nul;
  1579.       mktemp (Temp_File_Name'Address);
  1580.       The_File.Name := new String'(Temp_File_Name (1 .. 13));
  1581.  
  1582.       --  Append the name of the temporary file to the beginning of the
  1583.       --  Temp_File list which will be used for deleting all the temporary
  1584.       --  files after completion of the main program.
  1585.  
  1586.       Temp_Files := new Temp_File_Rec'(The_File.Name, Temp_Files);
  1587.    end Make_Temp_File_Name;
  1588.  
  1589.    -------------------------------
  1590.    -- Check_Multiple_File_Opens --
  1591.    -------------------------------
  1592.  
  1593.    procedure Check_Multiple_File_Opens is
  1594.    begin
  1595.       --  Allow a several opens to read an external file, but not one open to
  1596.       --  read and another open to write a external file.
  1597.  
  1598.       for J in Open_Files'range loop
  1599.          if Open_Files (J) /= null and then Open_Files (J).AFCB_In_Use then
  1600.             if The_File.Name.all = Open_Files (J).Name.all
  1601.               and then (The_File.Mode /= In_File
  1602.                          or else Open_Files (J).Mode /= In_File)
  1603.             then
  1604.                raise Use_Error; --  File already open
  1605.             end if;
  1606.          end if;
  1607.       end loop;
  1608.    end Check_Multiple_File_Opens;
  1609.  
  1610.    -----------------------------
  1611.    --  Page_Is_Not_Terminated --
  1612.    -----------------------------
  1613.  
  1614.    function Page_Is_Not_Terminated return Boolean is
  1615.    begin
  1616.       return not (The_File.Col = 1
  1617.         and then The_File.Line = 1
  1618.         and then The_File.Page /= 1);
  1619.    end Page_Is_Not_Terminated;
  1620.  
  1621.    ----------------
  1622.    -- Close_File --
  1623.    ----------------
  1624.  
  1625.    procedure Close_File is
  1626.       procedure Fclose (F : Text_IO.File_Ptr);
  1627.       pragma Import (C, fclose);
  1628.  
  1629.       File_Num : Integer := Open_Files'First;
  1630.  
  1631.    begin
  1632.       while File_Num <= Max_Num_Of_Files
  1633.          and then Open_Files (File_Num) /= The_File
  1634.       loop
  1635.          File_Num := File_Num + 1;
  1636.       end loop;
  1637.  
  1638.       if File_Num > Max_Num_Of_Files then
  1639.          raise Status_Error;
  1640.       end if;
  1641.  
  1642.       Fclose (The_File.Desc);
  1643.       The_File.AFCB_In_Use := False;
  1644.  
  1645.    end Close_File;
  1646.  
  1647.    ---------------------
  1648.    -- Load_Look_Ahead --
  1649.    ---------------------
  1650.  
  1651.    procedure Load_Look_Ahead (End_Of_File_Flag : Boolean) is
  1652.       C      : Character;
  1653.       Is_Eof : Boolean;
  1654.  
  1655.    begin
  1656.       --  Load first character of look ahead
  1657.  
  1658.       if Chars = 0 then
  1659.          Set_Char2 (Nul);
  1660.          Set_Char3 (Nul);
  1661.          C_Fgetc (The_File.Desc, C, Is_Eof);
  1662.  
  1663.          if Is_Eof then
  1664.             Set_Char1 (Nul);
  1665.             return;
  1666.          else
  1667.             Set_Char1 (C);
  1668.             Set_Chars (1);
  1669.          end if;
  1670.       end if;
  1671.  
  1672.       --  In the case where reading from the keyboard do not read more than
  1673.       --  1 character unless you are processing an end_of_file test.
  1674.  
  1675.       if Isatty (The_File.Desc) and then not End_Of_File_Flag then
  1676.          return;
  1677.       end if;
  1678.  
  1679.       --  Load second character of look ahead
  1680.  
  1681.       if Chars = 1 then
  1682.          Set_Char3 (Nul);
  1683.          C_Fgetc (The_File.Desc, C, Is_Eof);
  1684.  
  1685.          if Is_Eof then
  1686.             Set_Char2 (Nul);
  1687.             return;
  1688.          else
  1689.             Set_Char2 (C);
  1690.             Set_Chars (2);
  1691.          end if;
  1692.       end if;
  1693.  
  1694.       --  Leave lookahead with at most two characters loaded if standard
  1695.       --  input is the keyboard.
  1696.  
  1697.       if not Isatty (The_File.Desc) then
  1698.  
  1699.          --  Load third character of look ahead
  1700.  
  1701.          if Chars = 2 then
  1702.             C_Fgetc (The_File.Desc, C, Is_Eof);
  1703.  
  1704.             if Is_Eof then
  1705.                Set_Char3 (Nul);
  1706.                return;
  1707.             else
  1708.                Set_Char3 (C);
  1709.                Set_Chars (3);
  1710.             end if;
  1711.          end if;
  1712.       end if;
  1713.    end Load_Look_Ahead;
  1714.  
  1715.    --------------
  1716.    -- Get_Char --
  1717.    --------------
  1718.  
  1719.    function Get_Char return Character is
  1720.       C : Character;
  1721.  
  1722.    begin
  1723.       Load_Look_Ahead (False);
  1724.  
  1725.       if Chars = 0 then
  1726.          raise End_Error;  --  End of file on TEXT_IO input
  1727.       end if;
  1728.  
  1729.       C := Char1;
  1730.  
  1731.       --  Update lookahead
  1732.  
  1733.       Set_Char1 (Char2);
  1734.       Set_Char2 (Char3);
  1735.       Set_Char3 (Nul);
  1736.       Set_Chars (Chars - 1);
  1737.  
  1738.       --  Update PAGE and LINE counters if page mark or line feed read
  1739.  
  1740.       if C = Page_Mark then
  1741.          The_File.Page := The_File.Page + 1;
  1742.          The_File.Line := 1;
  1743.          The_File.Col := 1;
  1744.       elsif C = Line_Feed then
  1745.          The_File.Line := The_File.Line + 1;
  1746.          The_File.Col := 1;
  1747.       else
  1748.          The_File.Col := The_File.Col  + 1;
  1749.       end if;
  1750.  
  1751.       if Character'Pos (C) > 127 then
  1752.          raise Data_Error;  --  Character > 127 for TEXT_IO input"
  1753.       end if;
  1754.  
  1755.       return C;
  1756.    end Get_Char;
  1757.  
  1758.    ----------------
  1759.    -- Upper_Case --
  1760.    ----------------
  1761.  
  1762.    function Upper_Case (C : Character) return Character is
  1763.       V : constant Integer := 32;
  1764.  
  1765.    begin
  1766.       if C in 'a' .. 'z' then
  1767.          return Character'Val (Character'Pos (C) - V);
  1768.       else
  1769.          return C;
  1770.       end if;
  1771.    end Upper_Case;
  1772.  
  1773.    --------------
  1774.    -- Word_Sub --
  1775.    --------------
  1776.  
  1777.    procedure Word_Sub
  1778.      (A : Integer;
  1779.       B : Integer;
  1780.       O : out Boolean;
  1781.       R : out Integer)
  1782.    is
  1783.    begin
  1784.       R := A - B;
  1785.       O := ((A < 0 and then B > 0) or else (A > 0 and then B < 0))
  1786.            and then ((A < 0 and then R > 0) or else (A > 0 and then R < 0));
  1787.    end Word_Sub;
  1788.  
  1789.    --------------
  1790.    -- Word_Mul --
  1791.    --------------
  1792.  
  1793.    procedure Word_Mul
  1794.      (A : Integer;
  1795.       B : Integer;
  1796.       O : out Boolean;
  1797.       R : out Integer)
  1798.    is
  1799.    begin
  1800.       if A /= 0 then
  1801.          R := A * B;
  1802.          O := (B /= R / A) or else (A = -1 and then B < 0 and then R < 0);
  1803.       else
  1804.          R := 0;
  1805.          O := False;
  1806.       end if;
  1807.    end Word_Mul;
  1808.  
  1809.    ----------------
  1810.    -- Put_Blanks --
  1811.    ----------------
  1812.  
  1813.    procedure Put_Blanks (N : Integer) is
  1814.    begin
  1815.       for J in 1 .. N loop
  1816.          Fputc (The_File.Desc, ' ');
  1817.       end loop;
  1818.    end Put_Blanks;
  1819.  
  1820.    ----------------
  1821.    -- Put_Buffer --
  1822.    ----------------
  1823.  
  1824.    procedure Put_Buffer
  1825.      (Width    : Integer;
  1826.       Pad_Type : Character;
  1827.       Length   : Integer)
  1828.    is
  1829.       Pad           : Character := Pad_Type;
  1830.       Target_Length : Integer;
  1831.  
  1832.    begin
  1833.       if Length >= Width then
  1834.          Target_Length := Length;
  1835.          Pad := ' ';
  1836.       else
  1837.          Target_Length := Width;
  1838.       end if;
  1839.  
  1840.       --  Ensure the buffer size does not exceed the line length
  1841.  
  1842.       if The_File.Line_Length > 0 then
  1843.          if Count (Target_Length) > The_File.Line_Length then
  1844.             raise Layout_Error; --  "Line too big"
  1845.  
  1846.          --  New line if does not fit on current line
  1847.  
  1848.          elsif The_File.Col +
  1849.            Count (Target_Length) - 1 > The_File.Line_Length
  1850.          then
  1851.             Put_Line1;
  1852.          end if;
  1853.       end if;
  1854.  
  1855.       --  Output data with the required padding
  1856.  
  1857.       if Pad = 'L' then
  1858.          Put_Blanks (Width - Length);
  1859.       end if;
  1860.  
  1861.       for N in 0 .. Length - 1 loop
  1862.          Fputc (The_File.Desc, Work_String (N));
  1863.       end loop;
  1864.  
  1865.       The_File.Col := The_File.Col + Count (Target_Length);
  1866.  
  1867.       if Pad = 'T' then
  1868.          Put_Blanks (Width - Length);
  1869.       end if;
  1870.    end Put_Buffer;
  1871.  
  1872.    -----------------
  1873.    -- Image_Float --
  1874.    -----------------
  1875.  
  1876.    procedure Image_Float (Item : Float; Aft, Exp : Field) is
  1877.  
  1878.       procedure sprintf
  1879.         (Target     : Address;
  1880.          Fmt        : Address;
  1881.          Precision  : Natural;
  1882.          Value      : Long_Float;
  1883.          Length_Ptr : Address);
  1884.  
  1885.       pragma Import (C, sprintf);
  1886.  
  1887.       Fmt_E     : constant String := "%.*E%n" & Ascii.NUL;
  1888.       Fmt_F     : constant String := "%.*f%n" & Ascii.NUL;
  1889.       Fmt_Ptr   : Address;
  1890.       E_Pos     : Natural;
  1891.       Exp_Len   : Natural;
  1892.       Length    : aliased Natural;
  1893.       Precision : Natural;
  1894.  
  1895.    begin
  1896.       --  The value of Exp controls whether an exponent part is to appear. Use
  1897.       --  E or F format in the call to sprintf appropriately.
  1898.  
  1899.       if Exp = 0 then
  1900.          Fmt_Ptr := Fmt_F'Address;
  1901.       else
  1902.          Fmt_Ptr := Fmt_E'Address;
  1903.       end if;
  1904.  
  1905.       --  The number of digits of the fractional part is given by AFT, or is
  1906.       --  one if AFT equals zero.  [RM 14.3.8]
  1907.  
  1908.       if Aft = 0 then
  1909.          Precision := 1;
  1910.       else
  1911.          Precision := Aft;
  1912.       end if;
  1913.  
  1914.       sprintf (Target     => Work_String'Address,
  1915.                Fmt        => Fmt_Ptr,
  1916.                Precision  => Precision,
  1917.                Value      => Long_Float (Item),
  1918.                Length_Ptr => Length'Address);
  1919.  
  1920.       WS_Length := Length - 1;
  1921.  
  1922.       --  If the Exp parameter is not zero then a certain amount of correction
  1923.       --  to the exponent part of the image string is necessary since the
  1924.       --  semantics of sprintf do not allow the specification of the number
  1925.       --  of digits in the exponent as Ada allows. In the case of Exp of zero
  1926.       --  there is nothing left to do so return.
  1927.  
  1928.       if Exp = 0 then
  1929.          return;
  1930.       end if;
  1931.  
  1932.       --  Find the index of the 'E' in the image string.
  1933.  
  1934.       E_Pos := WS_Length;
  1935.       while Work_String (E_Pos) /= 'E' loop
  1936.          E_Pos := E_Pos - 1;
  1937.       end loop;
  1938.  
  1939.       Exp_Len := WS_Length - E_Pos;
  1940.  
  1941.       --  Since sprintf always use a minimum of two digits for the exponent
  1942.       --  if there is a leading zero in the exponent and Exp is specified as
  1943.       --  one it is necessary to trim the extra zero off and slide the
  1944.       --  remaining digit over one.
  1945.  
  1946.       if Exp = 1 then
  1947.          if Work_String (E_Pos + 2) = '0' then
  1948.             Work_String (E_Pos + 2) := Work_String (E_Pos + 3);
  1949.             WS_Length := WS_Length - 1;
  1950.          end if;
  1951.  
  1952.       --  Extra leading zeroes may need to be added in front of the exponent
  1953.       --  if the value of Exp is greater than the number of digits necessary
  1954.       --  to portray the tru exponent value.
  1955.  
  1956.       elsif Exp > Exp_Len then
  1957.          for I in reverse E_Pos + 2 .. WS_Length loop
  1958.             Work_String (I + Exp_Len - Exp) := Work_String (I);
  1959.          end loop;
  1960.  
  1961.          for I in E_Pos + 2 .. E_Pos + 1 + Exp - Exp_Len loop
  1962.             Work_String (I) := '0';
  1963.          end loop;
  1964.  
  1965.          WS_Length := WS_Length + Exp - Exp_Len;
  1966.       end if;
  1967.    end Image_Float;
  1968.  
  1969.    -------------------
  1970.    -- Image_Integer --
  1971.    -------------------
  1972.  
  1973.    procedure Image_Integer (Item : Integer; Base : Integer) is
  1974.       P, Q   : Integer;
  1975.       Digit  : Integer;
  1976.       Buffer : Integer := Item;
  1977.  
  1978.    begin
  1979.       P := 0;
  1980.       if Base /= 10 then
  1981.          if Base > 10 then
  1982.             Work_String (P) := '1';
  1983.             Work_String (P + 1) := Character'Val
  1984.                                      (Character'Pos ('0') + Base - 10);
  1985.             Work_String (P + 2) := '#';
  1986.             P := P + 3;
  1987.          else
  1988.             Work_String (P) := Character'Val (Character'Pos ('0') + Base);
  1989.             Work_String (P + 1) := '#';
  1990.             P := P + 2;
  1991.          end if;
  1992.       end if;
  1993.  
  1994.       --  Deal with the sign. Note we work with the negative of the absolute
  1995.       --  value of the number so that we do not have to make special checks
  1996.       --  for the largest negative number ion the twos complement case.
  1997.  
  1998.       if Buffer < 0 then
  1999.          Work_String (P) := '-';
  2000.          P := P + 1;
  2001.       else
  2002.          Buffer := -Buffer;
  2003.       end if;
  2004.  
  2005.       --  Convert value to digit string in specified base
  2006.  
  2007.       if Buffer = 0 then
  2008.          Work_String (P) := '0';
  2009.          P := P + 1;
  2010.       else
  2011.          Q := 15;
  2012.  
  2013.          while Buffer /= 0 loop
  2014.             Digit := -(Buffer rem Base);
  2015.             Buffer := Buffer / Base;
  2016.  
  2017.             if Digit > 9 then
  2018.                Work_String (Q) := Character'Val (Character'Pos ('A')
  2019.                                                  + Digit - 10);
  2020.             else
  2021.                Work_String (Q) := Character'Val (Character'Pos ('0')
  2022.                                                  + Digit);
  2023.             end if;
  2024.  
  2025.             Q := Q - 1;
  2026.          end loop;
  2027.  
  2028.          for J in 1 .. 15 - Q loop
  2029.             Work_String (P) := Work_String (Q + J);
  2030.             P := P + 1;
  2031.          end loop;
  2032.       end if;
  2033.  
  2034.       if Base /= 10 then
  2035.          Work_String (P) := '#';
  2036.          P := P + 1;
  2037.       end if;
  2038.  
  2039.       WS_Length := P;
  2040.    end Image_Integer;
  2041.  
  2042.    -----------
  2043.    -- Getcp --
  2044.    -----------
  2045.  
  2046.    function Getcp return Character is
  2047.       C : Character;
  2048.  
  2049.    begin
  2050.       if Scanning_From_File then
  2051.          return Get_Char;
  2052.       else
  2053.          if WS_Index1 > WS_Length then
  2054.             raise End_Error;
  2055.          end if;
  2056.  
  2057.          WS_Index1 := WS_Index1 + 1;
  2058.          return Work_String (WS_Index1);
  2059.       end if;
  2060.    end Getcp;
  2061.  
  2062.    -----------
  2063.    -- Nextc --
  2064.    -----------
  2065.  
  2066.    function Nextc return Character is
  2067.    begin
  2068.       if Scanning_From_File then
  2069.          Load_Look_Ahead (False);
  2070.          return Char1;
  2071.       else
  2072.          if WS_Index1 < WS_Length then
  2073.             return Work_String (WS_Index1);
  2074.          else
  2075.             return Line_Feed;
  2076.          end if;
  2077.       end if;
  2078.    end Nextc;
  2079.  
  2080.    -----------
  2081.    -- Skipc --
  2082.    -----------
  2083.  
  2084.    procedure Skipc is
  2085.       C : Character;
  2086.  
  2087.    begin
  2088.       if Scanning_From_File then
  2089.          C := Get_Char;
  2090.       else
  2091.          WS_Index1 := WS_Index1 + 1;
  2092.       end if;
  2093.    end Skipc;
  2094.  
  2095.    -----------
  2096.    -- Copyc --
  2097.    -----------
  2098.  
  2099.    procedure Copyc is
  2100.       C : Character;
  2101.  
  2102.    begin
  2103.       if Scanning_From_File then
  2104.          C := Get_Char;
  2105.       else
  2106.          if WS_Index1 > WS_Length then
  2107.             raise Program_Error;
  2108.          else
  2109.             C := Work_String (WS_Index1);
  2110.             WS_Index1 := WS_Index1 + 1;
  2111.          end if;
  2112.       end if;
  2113.  
  2114.       Work_String (WS_Index2) := Upper_Case (C);
  2115.       WS_Index2 := WS_Index2 + 1;
  2116.    end Copyc;
  2117.  
  2118.    ------------------
  2119.    -- Copy_Integer --
  2120.    ------------------
  2121.  
  2122.    procedure Copy_Integer is
  2123.    begin
  2124.       Check_Digit;
  2125.       while Digit (Nextc) loop
  2126.          Copyc;
  2127.  
  2128.          if Nextc = '_' then
  2129.             Skipc;
  2130.             Check_Digit;
  2131.          end if;
  2132.       end loop;
  2133.    end Copy_Integer;
  2134.  
  2135.    ------------------------
  2136.    -- Copy_Based_Integer --
  2137.    ------------------------
  2138.  
  2139.    procedure Copy_Based_Integer is
  2140.    begin
  2141.       Check_Extended_Digit;
  2142.  
  2143.       while Extended_Digit (Nextc) loop
  2144.          Copyc;
  2145.  
  2146.          if Nextc = '_' then
  2147.             Skipc;
  2148.             Check_Extended_Digit;
  2149.          end if;
  2150.       end loop;
  2151.    end Copy_Based_Integer;
  2152.  
  2153.    -----------------
  2154.    -- Scan_Blanks --
  2155.    -----------------
  2156.  
  2157.    procedure Scan_Blanks is
  2158.       C : Character;
  2159.    begin
  2160.       if Scanning_From_File then
  2161.          loop
  2162.             Load_Look_Ahead (False);
  2163.  
  2164.             if Chars = 0 then
  2165.                raise End_Error;
  2166.             end if;
  2167.  
  2168.             C := Nextc;
  2169.  
  2170.             if C = ' '
  2171.               or else C = Ascii.HT
  2172.               or else C = Line_Feed
  2173.               or else C = Page_Mark
  2174.             then
  2175.                C := Getcp;
  2176.             else
  2177.                exit;
  2178.             end if;
  2179.          end loop;
  2180.  
  2181.       else
  2182.          while WS_Index1 <= WS_Length - 1 loop
  2183.             if Work_String (WS_Index1) = ' '
  2184.               or else Work_String (WS_Index1) = Ascii.HT
  2185.             then
  2186.                WS_Index1 := WS_Index1 + 1;
  2187.             else
  2188.                exit;
  2189.             end if;
  2190.          end loop;
  2191.       end if;
  2192.    end Scan_Blanks;
  2193.  
  2194.    ------------------------
  2195.    -- Setup_Fixed_Field --
  2196.    ------------------------
  2197.  
  2198.    procedure Setup_Fixed_Field (Width : Integer) is
  2199.       J : Integer := 0;
  2200.  
  2201.    begin
  2202.       loop
  2203.          Load_Look_Ahead (False);
  2204.  
  2205.          if Width /= J
  2206.            and then Chars /= 0
  2207.            and then Char1 /= Page_Mark
  2208.            and then Char1 /= Line_Feed
  2209.          then
  2210.             Work_String (J) := Get_Char;
  2211.             J := J + 1;
  2212.          else
  2213.             exit;
  2214.          end if;
  2215.       end loop;
  2216.  
  2217.       WS_Length := J;
  2218.       Scanning_From_File := False;
  2219.       WS_Index1 := 0;
  2220.    end Setup_Fixed_Field;
  2221.  
  2222.    --------------------------
  2223.    -- Test_Fixed_Field_End --
  2224.    --------------------------
  2225.  
  2226.    procedure Test_Fixed_Field_End is
  2227.    begin
  2228.       Scan_Blanks;
  2229.  
  2230.       if WS_Index1 < WS_Length then
  2231.          raise Data_Error;
  2232.       end if;
  2233.    end Test_Fixed_Field_End;
  2234.  
  2235.    -----------
  2236.    -- Alpha --
  2237.    -----------
  2238.  
  2239.    function Alpha (C : Character) return Boolean is
  2240.    begin
  2241.       return C in 'A' .. 'Z' or else C in 'a' .. 'z';
  2242.    end Alpha;
  2243.  
  2244.    --------------
  2245.    -- Alphanum --
  2246.    --------------
  2247.  
  2248.    function Alphanum (C : Character) return Boolean is
  2249.    begin
  2250.       return Alpha (C) or else C in '0' .. '9';
  2251.    end Alphanum;
  2252.  
  2253.    -------------
  2254.    -- Graphic --
  2255.    -------------
  2256.  
  2257.    function Graphic (C : Character) return Boolean is
  2258.       Low  : constant Integer := 32;
  2259.       High : constant Integer := 127;
  2260.  
  2261.    begin
  2262.       return Character'Pos (C) in Low .. High;
  2263.    end Graphic;
  2264.  
  2265.    -----------
  2266.    -- Digit --
  2267.    -----------
  2268.  
  2269.    function Digit (C : Character) return Boolean is
  2270.    begin
  2271.       return C in '0' .. '9';
  2272.    end Digit;
  2273.  
  2274.    --------------------
  2275.    -- Extended_Digit --
  2276.    --------------------
  2277.  
  2278.    function Extended_Digit (C : Character) return Boolean is
  2279.    begin
  2280.       return C in '0' .. '9' or else C in 'a' .. 'f' or else C in 'A' .. 'F';
  2281.    end Extended_Digit;
  2282.  
  2283.    ----------
  2284.    -- Sign --
  2285.    ----------
  2286.  
  2287.    function Sign (C : Character) return Boolean is
  2288.    begin
  2289.       return C = '-' or C = '+';
  2290.    end Sign;
  2291.  
  2292.    -----------------
  2293.    -- Check_Digit --
  2294.    -----------------
  2295.  
  2296.    procedure Check_Digit is
  2297.    begin
  2298.       if not (Nextc in '0' .. '9') then
  2299.          raise Data_Error;
  2300.       end if;
  2301.    end Check_Digit;
  2302.  
  2303.    ----------------
  2304.    -- Check_Hash --
  2305.    ----------------
  2306.  
  2307.    procedure Check_Hash (C : Character) is
  2308.    begin
  2309.       if Nextc /= C then
  2310.          raise Data_Error;
  2311.       end if;
  2312.  
  2313.       Skipc;
  2314.       Work_String (WS_Index2) := '#';
  2315.       WS_Index2 := WS_Index2 + 1;
  2316.    end Check_Hash;
  2317.  
  2318.    --------------------------
  2319.    -- Check_Extended_Digit --
  2320.    --------------------------
  2321.  
  2322.    procedure Check_Extended_Digit is
  2323.    begin
  2324.       if not Extended_Digit (Nextc) then
  2325.          raise Data_Error;
  2326.       end if;
  2327.    end Check_Extended_Digit;
  2328.  
  2329.    -----------------
  2330.    -- Range_Error --
  2331.    -----------------
  2332.  
  2333.    procedure Range_Error is
  2334.    begin
  2335.       raise Data_Error;
  2336.    end Range_Error;
  2337.  
  2338.    --------------
  2339.    -- Scan_Int --
  2340.    --------------
  2341.  
  2342.    function Scan_Int return Integer is
  2343.       Ival        : Integer := 0;
  2344.       Digit_Value : Integer;
  2345.       Overflow1   : Boolean;
  2346.       Overflow2   : Boolean;
  2347.  
  2348.    begin
  2349.       while WS_Index2 < WS_Length
  2350.         and then Digit (Work_String (WS_Index2))
  2351.       loop
  2352.          Digit_Value := Character'Pos (Work_String (WS_Index2))
  2353.                         - Character'Pos ('0');
  2354.          WS_Index2 := WS_Index2 + 1;
  2355.          Word_Mul (Ival, 10, Overflow1, Ival);
  2356.          Word_Sub (Ival, Digit_Value, Overflow2, Ival);
  2357.  
  2358.          if Overflow1 or else Overflow2 then
  2359.             while WS_Index2 < WS_Length
  2360.               and then Digit (Work_String (WS_Index2))
  2361.             loop
  2362.                WS_Index2 := WS_Index2 + 1;
  2363.             end loop;
  2364.             return 1;
  2365.          end if;
  2366.       end loop;
  2367.  
  2368.       return Ival;
  2369.    end Scan_Int;
  2370.  
  2371.    --------------------
  2372.    -- Scan_Based_Int --
  2373.    --------------------
  2374.  
  2375.    --  This routine scans a based Integer value fromt the string pointed by
  2376.    --  the global Integer WS_Index2. On exit WS_Index2 is updated to point
  2377.    --  to the first non-digit. The result returned is always negative. This
  2378.    --  allows the largest negative Integer value to be properly stored and
  2379.    --  converted. If overflow is detected, then the value +1 is returned to
  2380.    --  signal overflow.
  2381.  
  2382.    function Scan_Based_Int (Base : Integer) return Integer is
  2383.       Ival        : Integer := 0;
  2384.       Digit_Value : Integer;
  2385.       Overflow1   : Boolean;
  2386.       Overflow2   : Boolean;
  2387.  
  2388.    begin
  2389.       while WS_Index2 < WS_Length
  2390.         and then Extended_Digit (Work_String (WS_Index2))
  2391.       loop
  2392.          Word_Mul (Ival, Base, Overflow1, Ival);
  2393.          Digit_Value := Character'Pos (Work_String (WS_Index2))
  2394.                                        - Character'Pos ('0');
  2395.          WS_Index2 := WS_Index2 + 1;
  2396.  
  2397.          if Digit_Value > 9 then
  2398.             Digit_Value := Digit_Value - 7;
  2399.          end if;
  2400.  
  2401.          if Digit_Value >= Base then
  2402.             raise Data_Error;
  2403.          end if;
  2404.  
  2405.          Word_Sub (Ival, Digit_Value, Overflow2, Ival);
  2406.  
  2407.          if Overflow1 or else Overflow2 then
  2408.             while WS_Index2 < WS_Length
  2409.               and then Extended_Digit (Work_String (WS_Index2))
  2410.             loop
  2411.                WS_Index2 := WS_Index2 + 1;
  2412.             end loop;
  2413.             return 1;
  2414.          end if;
  2415.       end loop;
  2416.  
  2417.       return Ival;
  2418.    end Scan_Based_Int;
  2419.  
  2420.    ----------------------
  2421.    -- Scan_Integer_Val --
  2422.    ----------------------
  2423.  
  2424.    procedure Scan_Integer_Val (Fixed_Field : Boolean; Result : out Integer) is
  2425.       Ival     : Integer;
  2426.       Sign_Val : Character;
  2427.       C        : Character;
  2428.       Base     : Integer;
  2429.       Based    : Boolean;
  2430.       Exponent : Integer;
  2431.       Overflow : Boolean;
  2432.  
  2433.    begin
  2434.       --  First scan out item with the proper syntax and put it in Work_String
  2435.  
  2436.       WS_Index2 := 0;
  2437.  
  2438.       if Sign (Nextc) then
  2439.          Copyc;
  2440.       end if;
  2441.  
  2442.       Copy_Integer;
  2443.       C := Nextc;
  2444.  
  2445.       if C = '#' or else C = ':' then
  2446.          Skipc;
  2447.          Work_String (WS_Index2) := '#';
  2448.          WS_Index2 := WS_Index2 + 1;
  2449.          Copy_Based_Integer;
  2450.          Check_Hash (C);
  2451.          Based := True;
  2452.       else
  2453.          Based := False;
  2454.       end if;
  2455.  
  2456.       C := Nextc;
  2457.  
  2458.       if C = 'e' or else C = 'E' then
  2459.          Copyc;
  2460.          C := Nextc;
  2461.  
  2462.          if C = '+' or else C = '-' then
  2463.             Skipc;
  2464.          end if;
  2465.  
  2466.          Copy_Integer;
  2467.  
  2468.          if C = '-' then
  2469.             raise Data_Error;  --  Negative exponent in integer value
  2470.          end if;
  2471.       end if;
  2472.  
  2473.       if Fixed_Field then
  2474.          Test_Fixed_Field_End;
  2475.       end if;
  2476.  
  2477.       WS_Length := WS_Index2;
  2478.       Work_String (WS_Index2) := ' ';
  2479.  
  2480.       --  Now we have the Integer literal stored in Work_String
  2481.  
  2482.       WS_Index2 := 0;
  2483.  
  2484.       if Sign (Work_String (WS_Index2)) then
  2485.          Sign_Val := Work_String (WS_Index2);
  2486.          WS_Index2 := WS_Index2 + 1;
  2487.       else
  2488.          Sign_Val := '+';
  2489.       end if;
  2490.  
  2491.       if Based then
  2492.          Base := -Scan_Int;
  2493.  
  2494.          if not (Base in 2 .. 16) then
  2495.             raise Data_Error;
  2496.          end if;
  2497.  
  2498.          WS_Index2 := WS_Index2 + 1;
  2499.          Ival := Scan_Based_Int (Base);
  2500.          WS_Index2 := WS_Index2 + 1;
  2501.  
  2502.       else
  2503.          Ival := Scan_Int;
  2504.          Base := 10;
  2505.       end if;
  2506.  
  2507.       --  Number is in Ival (in negative form), deal with exponent.
  2508.  
  2509.       if Ival = 1 then
  2510.          Range_Error;
  2511.       end if;
  2512.  
  2513.       if Work_String (WS_Index2) = 'E' then
  2514.          WS_Index2 := WS_Index2 + 1;
  2515.          Exponent := Scan_Int;
  2516.  
  2517.          if Exponent < -64 or else Exponent = 1 then
  2518.             Range_Error;
  2519.          end if;
  2520.  
  2521.          while Exponent /= 0 loop
  2522.             Exponent := Exponent + 1;
  2523.             Word_Mul (Ival, Base, Overflow, Ival);
  2524.  
  2525.             if Overflow then
  2526.                Range_Error;
  2527.             end if;
  2528.          end loop;
  2529.       else
  2530.          WS_Index2 := WS_Index2 + 1;
  2531.       end if;
  2532.  
  2533.       if Sign_Val = '+' then
  2534.          Ival := -Ival;
  2535.  
  2536.          if Ival < 0 then
  2537.             Range_Error;
  2538.          end if;
  2539.       end if;
  2540.  
  2541.       Result := Ival;
  2542.    end Scan_Integer_Val;
  2543.  
  2544.    ------------------
  2545.    -- Scan_Integer --
  2546.    ------------------
  2547.  
  2548.    procedure Scan_Integer (Width : Integer; Result : out Integer) is
  2549.    begin
  2550.       if Width /= 0 then
  2551.          Setup_Fixed_Field (Width);
  2552.          Scan_Blanks;
  2553.  
  2554.          if WS_Index1 = WS_Length then
  2555.             raise Data_Error;  --  String is all blanks
  2556.          end if;
  2557.  
  2558.          Scan_Integer_Val (True, Result);
  2559.       else
  2560.          Scanning_From_File := True;
  2561.          Scan_Blanks;
  2562.          Scan_Integer_Val (False, Result);
  2563.       end if;
  2564.    end Scan_Integer;
  2565.  
  2566.    -------------------------
  2567.    -- Scan_Integer_String --
  2568.    -------------------------
  2569.  
  2570.    procedure Scan_Integer_String (Last : out Integer; Result : out Integer) is
  2571.    begin
  2572.       Scanning_From_File := False;
  2573.       Scan_Blanks;
  2574.  
  2575.       if WS_Index1 = WS_Length then
  2576.          raise End_Error;
  2577.       end if;
  2578.  
  2579.       Scan_Integer_Val (False, Result);
  2580.       Last := WS_Index1;
  2581.    end Scan_Integer_String;
  2582.  
  2583.    --------------------
  2584.    -- Scan_Real_Val --
  2585.    --------------------
  2586.  
  2587.    --  Procedure to scan a real value and return the result as a double real.
  2588.    --  A range exception is signalled if the value is out of range of allowed
  2589.    --  Ada real values, but no other range check is made.
  2590.  
  2591.    function Scan_Real_Val (Fixed_Field : Boolean) return Long_Float is
  2592.       Base         : Integer;        --  base as integer
  2593.       Based        : Boolean;        --  True if number is based
  2594.       Before_Point : Boolean;        --  True if before decimal point
  2595.       C            : Character;      --  character scanned
  2596.       Dbase        : Long_Float;     --  base as real
  2597.       Dig          : Integer;        --  next digit value
  2598.       Ddig         : Long_Float;     --  next digit as real
  2599.       Dval         : Long_Float;     --  value being scanned
  2600.       Exp_Sign_Val : Character;      --  sign of exponent
  2601.       Fraction     : Long_Float;     --  power of ten fraction after decimal pt
  2602.       Sign_Val     : Character;      --  sign of mantissa
  2603.       Exponent     : Integer;        --  value of exponent
  2604.  
  2605.    begin
  2606.       --  First scan out item with the proper syntax and put it in work_string
  2607.  
  2608.       WS_Index2 := 0;
  2609.  
  2610.       if Sign (Nextc) then
  2611.          Copyc;
  2612.       end if;
  2613.  
  2614.       Copy_Integer;
  2615.       C := Nextc;
  2616.  
  2617.       if C = '#' or else C = ':' then
  2618.          Skipc;
  2619.          Work_String (WS_Index2) := '#';
  2620.          WS_Index2 := WS_Index2 + 1;
  2621.          Copy_Based_Integer;
  2622.  
  2623.          if Nextc /= '.' then
  2624.             raise Data_Error; --  missing period in real value
  2625.          end if;
  2626.  
  2627.          Copyc;
  2628.          Copy_Based_Integer;
  2629.          Check_Hash (C);
  2630.          Based := True;
  2631.  
  2632.       else
  2633.          Based := False;
  2634.  
  2635.          if Nextc /= '.' then
  2636.             raise Data_Error; --  Missing period in real value
  2637.          end if;
  2638.  
  2639.          Copyc;
  2640.          Copy_Integer;
  2641.       end if;
  2642.  
  2643.       C := Nextc;
  2644.  
  2645.       if C = 'e' or else C = 'E' then
  2646.          Copyc;
  2647.          C := Nextc;
  2648.  
  2649.          if Sign (Nextc) then
  2650.             Copyc;
  2651.          end if;
  2652.  
  2653.          Copy_Integer;
  2654.       end if;
  2655.  
  2656.       if Fixed_Field then
  2657.          Test_Fixed_Field_End;
  2658.       end if;
  2659.  
  2660.       WS_Length := WS_Index2;
  2661.  
  2662.       --  Now we have the real literal stored in work_string, so prepare to
  2663.       --  convert the value, dealing first with setting the proper sign. Note
  2664.       --  that we can assume that the syntax of the literal is correct since
  2665.       --  we did all the checking above as we scanned it out.
  2666.  
  2667.       WS_Index2 := 0;
  2668.  
  2669.       if Sign (Work_String (WS_Index2)) then
  2670.          Sign_Val := Work_String (WS_Index2);
  2671.          WS_Index2 := WS_Index2 + 1;
  2672.       else
  2673.          Sign_Val := '+';
  2674.       end if;
  2675.  
  2676.       --  Acquire the proper base value. Note that scan_int returns the
  2677.       --  negative of the value scanned, with +1 indicating overflow which
  2678.       --  will be invalid.
  2679.  
  2680.       if Based then
  2681.          Base := Scan_Int;
  2682.  
  2683.          if Base not in -16 .. -2 then
  2684.             raise Data_Error;  --  Invalid base
  2685.          end if;
  2686.  
  2687.          Base := -Base;
  2688.          WS_Index2 := WS_Index2 + 1;
  2689.       else
  2690.          Base := 10;
  2691.       end if;
  2692.  
  2693.       Dbase := Long_Float (Base);
  2694.  
  2695.       --  Scan and convert digits
  2696.  
  2697.       Dval := 0.0;
  2698.       Before_Point := True;
  2699.  
  2700.       loop
  2701.          exit when WS_Index2 = WS_Length;
  2702.  
  2703.          if Work_String (WS_Index2) = '#' then
  2704.             WS_Index2 := WS_Index2 + 1;
  2705.             exit;
  2706.          end if;
  2707.  
  2708.          exit when (not Based) and then Work_String (WS_Index2) = 'E';
  2709.          C := Work_String (WS_Index2);
  2710.          WS_Index2 := WS_Index2 + 1;
  2711.  
  2712.          if C = '.' then
  2713.             Before_Point := False;
  2714.             Fraction := 1.0;
  2715.          else
  2716.             Dig := Character'Pos (C) - Character'Pos ('0');
  2717.  
  2718.             --  Convert hex digit
  2719.  
  2720.             if Dig > 9 then
  2721.                Dig := Dig - 7;
  2722.             end if;
  2723.  
  2724.             if Dig > Base then
  2725.                raise Data_Error; --  Digit > Base
  2726.             end if;
  2727.  
  2728.             Ddig := Long_Float (Dig);
  2729.  
  2730.             if Before_Point then
  2731.                Dval := Dval * Dbase + Ddig;
  2732.                --  ???
  2733.                --  if Dval > ADA_MAX_REAL then
  2734.                --     Range_Error;
  2735.                --  end if;
  2736.             else
  2737.                Fraction := Fraction / Long_Float (Base);
  2738.                Dval := Dval + Ddig * Fraction;
  2739.             end if;
  2740.          end if;
  2741.       end loop;
  2742.  
  2743.       --  Deal with exponent if present
  2744.  
  2745.       if Work_String (WS_Index2) = 'E' then
  2746.          WS_Index2 := WS_Index2 + 1;
  2747.  
  2748.          if Sign (Work_String (WS_Index2)) then
  2749.             Exp_Sign_Val := Work_String (WS_Index2);
  2750.             WS_Index2 := WS_Index2 + 1;
  2751.          else
  2752.             Exp_Sign_Val := '+';
  2753.          end if;
  2754.  
  2755.          Exponent := Scan_Int;
  2756.  
  2757.          --  A value of +1 in exponent means that scan_int detected overflow.
  2758.          --  This is not yet a range error. If the mantissa is 0 or 1, the
  2759.          --  effect is as if we had an exponent of 1.
  2760.  
  2761.          if Exponent = 1 then
  2762.             if Dval = 0.0 or else Dval = 1.0 then
  2763.                Exponent := 1;
  2764.  
  2765.             --  If we have a positive exponent, then if the mantissa is greater
  2766.             --  than 1.0, we do have an overflow, otherwise if the mantissa is
  2767.             --  less than 1.0, we have an underflow situation giving a result
  2768.             --  of zero.
  2769.  
  2770.             elsif Exp_Sign_Val = '+' then
  2771.                if Dval > 1.0 then
  2772.                   Range_Error;
  2773.                else
  2774.                   Dval := 0.0;
  2775.                end if;
  2776.  
  2777.             --  For a negative exponent, the situation is the other way round,
  2778.             --  since we want in effect the reciprocal of the value for the
  2779.             --  positive case.
  2780.  
  2781.             else
  2782.                if Dval > 1.0 then
  2783.                   Dval := 0.0;
  2784.                else
  2785.                   Range_Error;
  2786.                end if;
  2787.             end if;
  2788.  
  2789.          --  If no overflow, get abs value of exponent (scan_int returned -exp)
  2790.  
  2791.          else
  2792.             Exponent := -Exponent;
  2793.          end if;
  2794.  
  2795.          --  An optimization: if the mantissa is zero, save a lot of time
  2796.          --  in converting silly numbers like 0E+25000 by resetting exponent.
  2797.  
  2798.          if Dval = 0.0 then
  2799.             Exponent := 0;
  2800.          end if;
  2801.  
  2802.          --  Adjust mantissa by exponent, using proper exponent sign
  2803.  
  2804.          if Exp_Sign_Val = '+' then
  2805.             while Exponent > 0 loop
  2806.                Dval := Dval * Dbase;
  2807.                --  ???
  2808.                --  if Dval > ADA_MAX_REAL then
  2809.                --     Range_Error;
  2810.                --  end if;
  2811.                Exponent := Exponent - 1;
  2812.             end loop;
  2813.          else
  2814.             while Exponent > 0 loop
  2815.                Dval := Dval / Dbase;
  2816.                Exponent := Exponent - 1;
  2817.             end loop;
  2818.          end if;
  2819.       end if;
  2820.  
  2821.       --  Return scanned value with proper sign
  2822.  
  2823.       if Sign_Val = '+' then
  2824.          return Dval;
  2825.       else
  2826.          return -Dval;
  2827.       end if;
  2828.    end Scan_Real_Val;
  2829.  
  2830.    --------------------
  2831.    -- Scan_Float_Val --
  2832.    --------------------
  2833.  
  2834.    function Scan_Float_Val (Fixed_Field : Boolean) return Float is
  2835.       Dval : Long_Float;
  2836.  
  2837.    begin
  2838.       Dval := Scan_Real_Val (Fixed_Field);
  2839.       --  ??? Check that value is in range. Unimplemented for now.
  2840.       return Float (Dval);
  2841.    end Scan_Float_Val;
  2842.  
  2843.    ----------------
  2844.    -- Scan_Float --
  2845.    ----------------
  2846.  
  2847.    function Scan_Float (Width : Natural) return Float is
  2848.       Result : Float;
  2849.  
  2850.    begin
  2851.       if Width /= 0 then
  2852.          Setup_Fixed_Field (Width);
  2853.          Scan_Blanks;
  2854.  
  2855.          if WS_Index1 = WS_Length then
  2856.             raise Data_Error; --  String is all blanks
  2857.          end if;
  2858.  
  2859.          Result := Scan_Float_Val (True);
  2860.       else
  2861.          Scanning_From_File := True;
  2862.          Scan_Blanks;
  2863.          Result := Scan_Float_Val (False);
  2864.       end if;
  2865.  
  2866.       return Result;
  2867.    end Scan_Float;
  2868.  
  2869.    -----------------------
  2870.    -- Scan_Float_String --
  2871.    -----------------------
  2872.  
  2873.    procedure Scan_Float_String (Last : out Integer; Result : out Float) is
  2874.    begin
  2875.       Scanning_From_File := False;
  2876.       Scan_Blanks;
  2877.  
  2878.       if WS_Index1 = WS_Length then
  2879.          raise End_Error; --  String is all blanks
  2880.       end if;
  2881.  
  2882.       Result := Scan_Float_Val (False);
  2883.       Last := WS_Index1;
  2884.    end Scan_Float_String;
  2885.  
  2886.    ---------------
  2887.    -- Scan_Enum --
  2888.    ---------------
  2889.  
  2890.    procedure Scan_Enum (Last : out Natural) is
  2891.    begin
  2892.       Scan_Blanks;
  2893.  
  2894.       if not Scanning_From_File and then WS_Index1 = WS_Length then
  2895.          raise End_Error;  --  String is all blanks
  2896.       end if;
  2897.  
  2898.       WS_Index2 := 0;
  2899.  
  2900.       --  Try identifier
  2901.  
  2902.       if Alpha (Nextc) then
  2903.          while Alphanum (Nextc) loop
  2904.             Copyc;
  2905.  
  2906.             if Nextc = '_' then
  2907.                Copyc;
  2908.             end if;
  2909.          end loop;
  2910.  
  2911.       elsif Nextc = ''' then
  2912.  
  2913.       --  Look for an ending quote.
  2914.  
  2915.          Copyc;
  2916.  
  2917.          if Graphic (Nextc) then
  2918.             Work_String (WS_Index2) := Getcp;
  2919.             WS_Index2 := WS_Index2 + 1;
  2920.  
  2921.             if Nextc = ''' then
  2922.                Copyc;
  2923.             end if;
  2924.          else
  2925.             raise Data_Error;
  2926.          end if;
  2927.  
  2928.       else
  2929.          raise Data_Error;
  2930.       end if;
  2931.  
  2932.       WS_Length := WS_Index2;
  2933.       Last := WS_Index1;
  2934.    end Scan_Enum;
  2935.  
  2936.    --------------------------
  2937.    -- Text_IO_Finalization --
  2938.    --------------------------
  2939.  
  2940.    procedure Text_IO_Finalization is
  2941.    begin
  2942.       --  Close all open files except stdin, stdout and stderr
  2943.  
  2944.       for J in 4 .. Open_Files'Last loop
  2945.          if Open_Files (J) /= null
  2946.            and then Open_Files (J).AFCB_In_Use
  2947.            and then Open_Files (J).Mode /= In_File
  2948.          then
  2949.             Close_File;
  2950.          end if;
  2951.       end loop;
  2952.  
  2953.       --  Delete temporary files upon completion of the main program
  2954.  
  2955.       while (Temp_Files /= null) loop
  2956.          Unlink (Temp_Files.File_Name.all);
  2957.          Temp_Files := Temp_Files.Next;
  2958.       end loop;
  2959.    end Text_IO_Finalization;
  2960.  
  2961.    -----------
  2962.    -- Fopen --
  2963.    -----------
  2964.  
  2965.    function Fopen (Name : String; Typ : File_Mode) return Text_IO.File_Ptr is
  2966.       function C_Fopen (Name, Typ : Address) return Text_IO.File_Ptr;
  2967.       pragma Import (C, C_Fopen, "fopen");
  2968.  
  2969.       Name1 : String (Name'First .. Name'Last + 1);
  2970.       Read_Only : String (1 .. 3) := "rt";
  2971.       Write_Only : String (1 .. 3) := "wt";
  2972.  
  2973.    begin
  2974.       Name1 (Name'range) := Name;
  2975.       Name1 (Name1'Last) := Nul;
  2976.       Read_Only (3) := Nul;
  2977.       Write_Only (3) := Nul;
  2978.  
  2979.       if Typ = In_File then
  2980.          return C_Fopen (Name1'Address, Read_Only'Address);
  2981.       else
  2982.          return C_Fopen (Name1'Address, Write_Only'Address);
  2983.       end if;
  2984.    end Fopen;
  2985.  
  2986.    ------------
  2987.    -- Fclose --
  2988.    ------------
  2989.  
  2990.    procedure Fclose (P : Text_IO.File_Ptr) is
  2991.       procedure C_Fclose (P : Text_IO.File_Ptr);
  2992.       pragma Import (C, C_Fclose, "fclose");
  2993.  
  2994.    begin
  2995.       C_Fclose (P);
  2996.    end Fclose;
  2997.  
  2998.    ------------
  2999.    -- Unlink --
  3000.    ------------
  3001.  
  3002.    procedure Unlink (Name : String) is
  3003.       procedure C_Unlink (Name : Address);
  3004.       pragma Import (C, C_Unlink, "unlink");
  3005.  
  3006.       Name1 : String (Name'First .. Name'Last + 1);
  3007.  
  3008.    begin
  3009.       Name1 (Name'range) := Name;
  3010.       Name1 (Name1'Last) := Nul;
  3011.       C_Unlink (Name1'Address);
  3012.    end Unlink;
  3013.  
  3014.    ------------
  3015.    -- Isatty --
  3016.    ------------
  3017.  
  3018.    function Isatty (F : Text_IO.File_Ptr) return Boolean is
  3019.       function C_Isatty (I : Integer) return Boolean;
  3020.       pragma Import (C, C_Isatty, "isatty");
  3021.  
  3022.       function C_Fileno (F : Text_IO.File_Ptr) return Integer;
  3023.       pragma Import (C, C_Fileno, "fileno");
  3024.  
  3025.    begin
  3026.       return C_Isatty (C_Fileno (F));
  3027.    end Isatty;
  3028.  
  3029.  
  3030.    -------------
  3031.    -- C_Fgetc --
  3032.    -------------
  3033.  
  3034.    procedure C_Fgetc
  3035.      (F      : Text_IO.File_Ptr;
  3036.       C      : out Character;
  3037.       Is_Eof : out Boolean)
  3038.    is
  3039.       I      : Integer;
  3040.       function Fgetc (F : Text_IO.File_Ptr) return Integer;
  3041.       pragma Import (C, Fgetc, "fgetc");
  3042.  
  3043.    begin
  3044.       I := Fgetc (F);
  3045.       Is_Eof := I = -1;
  3046.  
  3047.       if not Is_Eof then
  3048.          C := Character'Val (I);
  3049.       end if;
  3050.    end C_Fgetc;
  3051.  
  3052.    -------------
  3053.    -- C_Fputc --
  3054.    -------------
  3055.  
  3056.    procedure Fputc (F : Text_IO.File_Ptr; C : Character) is
  3057.       procedure C_Fputc (C : Character; F : Text_IO.File_Ptr);
  3058.       pragma Import (C, C_Fputc, "fputc");
  3059.  
  3060.    begin
  3061.       C_Fputc (C, F);
  3062.    end Fputc;
  3063.  
  3064.    -----------
  3065.    -- Stdin --
  3066.    ------------
  3067.  
  3068.    function Stdin return Text_IO.File_Ptr is
  3069.       function C_Stdin return Text_IO.File_Ptr;
  3070.       pragma Import (C, C_Stdin);
  3071.  
  3072.    begin
  3073.       return C_Stdin;
  3074.    end Stdin;
  3075.  
  3076.    ------------
  3077.    -- Stdout --
  3078.    ------------
  3079.  
  3080.    function Stdout return Text_IO.File_Ptr is
  3081.       function C_Stdout return Text_IO.File_Ptr;
  3082.       pragma Import (C, C_Stdout);
  3083.  
  3084.    begin
  3085.       return C_Stdout;
  3086.    end Stdout;
  3087.  
  3088.    ------------
  3089.    -- Stderr --
  3090.    ------------
  3091.  
  3092.    function Stderr return Text_IO.File_Ptr is
  3093.       function C_Stderr return Text_IO.File_Ptr;
  3094.       pragma Import (C, C_Stderr);
  3095.  
  3096.    begin
  3097.       return C_Stderr;
  3098.    end Stderr;
  3099.  
  3100. begin
  3101.  
  3102.    --  Initialization of Standard Input
  3103.  
  3104.    Standard_In := new AFCB'(AFCB_In_Use => True,
  3105.      Desc => Stdin,
  3106.      Name => new String'("Standard_Input"),
  3107.      Form => new String'("rt"),
  3108.      Mode => In_File,
  3109.      Col  => 1,
  3110.      Line => 1,
  3111.      Page => 1,
  3112.      Line_Length => 0,
  3113.      Page_Length => 0,
  3114.      Count => 0,
  3115.      Look_Ahead => "   ");
  3116.  
  3117.    --  Initialization of Standard Output
  3118.  
  3119.    Standard_Out := new AFCB'(AFCB_In_Use => True,
  3120.      Desc => Stdout,
  3121.      Name => new String'("Standard_Output"),
  3122.      Form => new String'("wt"),
  3123.      Mode => Out_File,
  3124.      Col  => 1,
  3125.      Line => 1,
  3126.      Page => 1,
  3127.      Line_Length => 0,
  3128.      Page_Length => 0,
  3129.      Count => 0,
  3130.      Look_Ahead => "   ");
  3131.  
  3132.    --  Initialization of Standard Error
  3133.  
  3134.    Standard_Err := new AFCB'(AFCB_In_Use => True,
  3135.      Desc => Stderr,
  3136.      Name => new String'("Standard_Error"),
  3137.      Form => new String'("wt"),
  3138.      Mode => Out_File,
  3139.      Col  => 1,
  3140.      Line => 1,
  3141.      Page => 1,
  3142.      Line_Length => 0,
  3143.      Page_Length => 0,
  3144.      Count => 0,
  3145.      Look_Ahead => "   ");
  3146.  
  3147.    Current_In  := Standard_In;
  3148.    Current_Out := Standard_Out;
  3149.    Current_Err := Standard_Err;
  3150.  
  3151.    Open_Files (Open_Files'First + 0) := Standard_In;
  3152.    Open_Files (Open_Files'First + 1) := Standard_Out;
  3153.    Open_Files (Open_Files'First + 2) := Standard_Err;
  3154.  
  3155. end Ada.Text_IO.Aux;
  3156.